qthighway/xqservice/src/xqaiwrequest.cpp
branchRCL_3
changeset 9 5d007b20cfd0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qthighway/xqservice/src/xqaiwrequest.cpp	Tue Aug 31 16:02:37 2010 +0300
@@ -0,0 +1,657 @@
+/*
+* 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 <QObject>
+#include <qglobal.h>
+
+#include "xqservicelog.h"
+#include "xqaiwservicedriver.h"
+#include "xqaiwfiledriver.h"
+#include "xqaiwuridriver.h"
+#include "xqaiwrequest.h"
+
+/*!
+    \class XQAiwRequest
+    \inpublicgroup QtBaseModule
+
+    \ingroup ipc
+    \brief Encapsulates the core functionality of the interworking requests
+    
+    The XQAiwRequest class encapsulates the core functionality of the interworking requests and hides the implementation details. 
+    This object is created by the XQApplicationManager::create factory method.
+    
+    This class is a part of API to be used by the applications instead of using XQServiceRequest directly.
+    
+    The Application Manager API offers centric place for applications UIs to handle application to application interworking use cases, like:
+    - Synchronous out-of-process service call from client to service provider, where service provider needs to complete the request before
+      control comes back to requesting client.
+    - Asynchronous out-of-process service call from client to service provider, where Service provider completes the request whenever suitable.
+      The control returns back requesting as soon the service provider has received the asynchronous call (can be applied to notifications as well).
+    - Embedded out-of-process service call. In this case window groups are chained and "Back" returns to client window.
+    - Any named Qt type in the Qt meta-object system can be used as a service call parameter or return value. Also own, custom meta-types are supported.
+    - Launched service provider application (.exe) if not already running when client makes service call to it.
+    - List and discover services dynamically.
+    - Apply UI related options upon service launch, like "launch as embedded", "launch to foreground" and "launch to backround".
+    - Opening files to be viewed by a file viewing interface.
+    - Opening URI to be viewed by a URI viewing interface. Includes also launching activity URIs (appto) as fire-and-forget manner.
+    - Miscellanous AIW support, like get service stasus or get DRM attributes.
+    
+    See the "examples/appmgrclient" included in the QtHighway release for usage examples.
+    
+    <b>Example usage:</b> \n
+    The usage pattern for all the XQAiwRequest variants implemented as service providers , interface, QUrl, QFile, is similar both embedded
+    and non-embedded usage.
+    \code
+        // Recommended way is to add XQApplicationManager as member variable to class
+        // Later on when caching of services
+        // You can use the class also as local variable.
+        class Client
+        {
+
+        public:
+             // Service access
+            bool accessService(void);
+
+        private slots:
+                void handleOk(const QVariant &result);
+                void handleError(int errorCode, const QString& errorMessage);
+        private:
+              XQApplicationManager mAiwMgr;
+        };
+
+
+        //  In client.cpp
+        bool Client::accessService(void)
+        {
+            QString parameter1("+3581234567890");
+            int parameter2 = 3;
+
+            bool embedded=true;  // or false
+
+            XQAiwRequest *request;
+            // Create request by interface name, the very first service implementation
+            // applied.
+            request = mAiwMgr.create("Interface", "functionName2(QString, int)", embedded);
+
+            // If dedicated service is wanted, apply this 
+            // request = mAiwMgr.create("Service", "Interface", 
+            //                          "functionName2(QString, int)", embedded);
+
+            if (request == NULL)
+            {
+                // Service not found 
+                return false;
+            }
+
+            // Connect result handling signal
+            connect(request, SIGNAL(requestOk(const QVariant&)), this, SLOT(handleOk(const QVariant&)));
+            // Connect error handling signal or apply lastError function instead.
+            connect(request, SIGNAL(requestError(int,const QString&)), this, SLOT(handleError(int,const QString&)));
+
+            // Set function parameters
+           QList<QVariant> args;
+           args << parameter1;
+           args << parameter2;
+           request->setArguments(args);
+
+           // In this example, request embedded launch (window groups chained)
+           request->setEmbedded(true);
+
+           // Send the request
+           bool res = request.send();
+           if  (!res) 
+           {
+               // Request failed. 
+              return false;
+           }
+         
+           // If making multiple requests to same service, you can save the request as member variable
+           // In this example all done.
+           delete request;
+           return true;
+        }
+
+        void Client::handleOk(const QVariant& result)
+        {
+           // Handle result here or just save them.
+           // Result could be a service specific error code also.
+           // 
+        }
+
+        void Client::handleError(int errorCode, const QString& errorMessage)
+        {
+           // Handle error
+        }
+    \endcode
+    
+    \sa XQApplicationManager
+*/
+
+/*!
+    Constructs interworking request to service application by the given interface \a descriptor
+    which points to the dedicated implementation. The service application is not started during
+    creation of the request.
+    \param descriptor Points to the dedicated service implementation. Obtained via the XQApplicationManager::list function.
+    \param operation Service function to be called, equals \a message parameter in XQServiceRequest.
+    \param embedded True if window groups should be chained, false otherwise
+    \return Constructed interworking request to service application object.
+*/
+XQAiwRequest::XQAiwRequest(const XQAiwInterfaceDescriptor& descriptor, const QString &operation, bool embedded)
+    : QObject(),
+      currentRequest(NULL),
+      errorMsg(),
+      errorCode(0),
+      completeSignalConnected(false),
+      errorSignalConnected(false)
+{
+
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::XQAiwRequest: %s %s,%d,%x",
+                          qPrintable(descriptor.interfaceName()),
+                          qPrintable(operation),
+                          embedded,
+                          descriptor.property(XQAiwInterfaceDescriptor::ImplementationId).toInt());
+    
+    // Initialize service request
+    // The XQServiceRequest should actually accept service descriptor as input....
+    currentRequest = new XQAiwServiceDriver(descriptor, operation);
+    if (currentRequest)
+    {
+        currentRequest->setEmbedded(embedded);
+    }
+}
+
+/*!
+    Constructs interworking request to service application by the given uri and the interface \a descriptor
+    which points to the dedicated implementation. The service application is not started during
+    creation of the request.
+    \param uri Uri for the given interworking request to service application.
+    \param descriptor Points to the dedicated service implementation. Obtained via the XQApplicationManager::list function.
+    \param operation Service function to be called, equals \a message parameter in XQServiceRequest.
+    \return Constructed interworking request to service application object.
+*/
+XQAiwRequest::XQAiwRequest(
+    const QUrl &uri, const XQAiwInterfaceDescriptor& descriptor, const QString &operation)
+    : QObject(),
+      currentRequest(NULL),
+      errorMsg(),
+      errorCode(0),
+      completeSignalConnected(false),
+      errorSignalConnected(false)
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::XQAiwRequest (uri): %s %s,%x",
+                          qPrintable(descriptor.interfaceName()),
+                          qPrintable(operation),
+                          descriptor.property(XQAiwInterfaceDescriptor::ImplementationId).toInt());
+
+    if (XQAiwUriDriver::hasCustomHandler(uri))
+    {
+        // Custom handling goes via URI driver
+        currentRequest = new XQAiwUriDriver(uri, descriptor, operation);
+    }
+    else
+    {
+        // Otherwise, apply service based URI access
+        currentRequest = new XQAiwServiceDriver(descriptor, operation);
+    }
+    
+}
+
+
+/*!
+    Constructs interworking request to service application by the file and the interface \a descriptor
+    which points to the dedicated implementation. The service application is not started during
+    creation of the request.
+    \param file File for the given interworking request to service application.
+    \param descriptor Points to the dedicated service implementation. Obtained via the XQApplicationManager::list function.
+    \param operation Service function to be called, equals \a message parameter in XQServiceRequest.
+    \return Constructed interworking request to service application object.
+*/
+XQAiwRequest::XQAiwRequest(
+    const QFile &file, const XQAiwInterfaceDescriptor& descriptor, const QString &operation)
+    : QObject(),
+     currentRequest(NULL),
+      errorMsg(),
+      errorCode(0),
+      completeSignalConnected(false),
+      errorSignalConnected(false)
+{
+
+   XQSERVICE_DEBUG_PRINT("XQAiwRequest::XQAiwRequest (file): %s %x",
+                          qPrintable(file.fileName()),
+                          descriptor.property(XQAiwInterfaceDescriptor::ImplementationId).toInt());
+
+    // Initialize file service request
+   if (!descriptor.interfaceName().isEmpty())
+   {
+       // Apply normal service request
+       XQSERVICE_DEBUG_PRINT("Apply service driver");
+       currentRequest = new XQAiwServiceDriver(descriptor, operation);
+   }
+   else 
+   {
+       // The is no service provider for the file.
+       // So as backup plan, apply file driver to handle non-service file launches
+       XQSERVICE_DEBUG_PRINT("Apply file driver");
+       currentRequest = new XQAiwFileDriver(file, descriptor, operation);
+   }
+       
+}
+
+/*!
+    Constructs interworking request to service application by the sharable file and the interface \a descriptor
+    which points to the dedicated implementation. The service application is not started during
+    creation of the request.
+    \param file Sharable file for the given interworking request to service application.
+    \param descriptor Points to the dedicated service implementation. Obtained via the XQApplicationManager::list function.
+    \param operation Service function to be called, equals \a message parameter in XQServiceRequest.
+    \return Constructed interworking request to service application object.
+*/
+XQAiwRequest::XQAiwRequest(
+     const XQSharableFile &file, const XQAiwInterfaceDescriptor& descriptor, const QString &operation)
+    : QObject(),
+      currentRequest(NULL),
+      errorMsg(),
+      errorCode(0),
+      completeSignalConnected(false),
+      errorSignalConnected(false)
+{
+
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::XQAiwRequest (file handle): %x",
+                          descriptor.property(XQAiwInterfaceDescriptor::ImplementationId).toInt());
+
+    // Initialize file service request
+    if (!descriptor.interfaceName().isEmpty())
+    {
+       // Apply normal service request
+        XQSERVICE_DEBUG_PRINT("Apply service driver");
+        currentRequest = new XQAiwServiceDriver(descriptor, operation);
+    }
+    else 
+    {
+       // The is no service provider for the file.
+       // So as backup plan, apply file driver to handle non-service file launches
+        XQSERVICE_DEBUG_PRINT("Apply file driver");
+        currentRequest = new XQAiwFileDriver(file, descriptor, operation);
+    }
+
+}
+
+
+XQAiwRequest::~XQAiwRequest()
+{
+    XQSERVICE_DEBUG_PRINT("~XQAiwRequest::XQAiwRequest");
+
+    // Disconnect signals
+    if (completeSignalConnected)
+    {
+        disconnect(currentRequest, SIGNAL(requestOk(const QVariant&)), this, SLOT(handleAsyncResponse(const QVariant&)));
+    }
+    if (errorSignalConnected)
+    {
+        disconnect(currentRequest, SIGNAL(requestError(int,const QString&)), this, SLOT(handleAsyncError(int)));
+    }
+    
+    delete currentRequest; // Destructor cancels the async request
+    
+    for (int i=0; i<actionList.size(); i++)
+    {
+        delete actionList[i];
+    }
+}
+
+/*!
+    Create a QAction related to request from the registration data. Caller can
+    add the action to wanted UI widget. When the action  is triggered the XQAiwRequest
+    emits triggered() signal for caller.
+    The XQAiwRequest owns the action (caller shall not delete the action object).
+    \return QAction object, if there was action attached to request. Otherwise 0.
+*/
+QAction *XQAiwRequest::createAction()
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::createAction");
+
+    QAction * action = currentRequest->createAction();
+    if (action)
+    {
+        if (!connect(action, SIGNAL(triggered(bool)), this, SLOT(sendFromAction(bool)))) {
+            XQSERVICE_CRITICAL_PRINT("Failed to connect QAction triggered signal to XQAiwRequest.");
+        }
+        actionList.append(action);
+        return action; 
+    }
+    
+    return NULL;
+}
+
+/*!
+    Set arguments for the request. This shall be called before sending
+    add the action to wanted UI widget. For the attached action, the
+    triggered() signal emitted by the request is the last chance to
+    add aguments.
+    \param arguments List of arguments that will be transferred to service provider function
+                     to be called
+*/
+void XQAiwRequest::setArguments(const QList<QVariant> &arguments)
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::setArguments");
+    currentRequest->setArguments(arguments);
+}
+
+
+/*!
+    Returns the last error code occured.
+    IPC errors:
+        - ENoError          = 0
+        - EConnectionError  = -5000,  (Server might be busy)
+        - EConnectionClosed = -4999,  
+        - EServerNotFound   = -4998,
+        - EIPCError         = -4997,
+        - EUnknownError     = -4996,
+        - ERequestPending   = -4995,  (already pending request exists)
+        - EMessageNotFound  = -4994,
+        - EArgumentError    = -4993
+    \return Error code as integer value.
+    \sa xqserviceglobal.h for error codes
+
+*/
+int XQAiwRequest::lastError() const
+{
+    int err = currentRequest->lastError();
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::lastError %d", err);
+    return err;
+}
+
+/*!
+    Returns the last error as text for debugging purposes.
+    The content and details of the text may vary over API
+    development time evolution.
+    \return Error code as QString value.
+*/
+const QString& XQAiwRequest::lastErrorMessage() const
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::lastErrorMessage");
+    return currentRequest->lastErrorMessage();
+}
+
+
+/*!
+    Returns the implementation descriptor of a service attached to request.
+    Caller can check meta-data information of the request.
+    \return Implementation descriptor attached to the request.
+*/
+const XQAiwInterfaceDescriptor &XQAiwRequest::descriptor() const 
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::descriptor");
+    return currentRequest->descriptor();
+}
+
+/*!
+    Starts the service application if necessary and sends request on-ward.
+    The results are delivered via requestOk() and requestError() signals.
+    If the request is synchronous, the client application is blocked until
+    service provider completes the request.
+    \return True on success, false otherwise
+*/
+bool XQAiwRequest::send()
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::send");
+
+    // do request
+    if (sendExecute())
+    {
+        if (currentRequest->isSynchronous())
+        {
+            XQSERVICE_DEBUG_PRINT("XQAiwRequest::emit requestOk");
+            emit requestOk(result);
+            result.clear();
+        }
+        return true;
+    } else
+    {
+        XQSERVICE_DEBUG_PRINT("XQAiwRequest::emit requestError");
+        emit requestError(lastError(), lastErrorMessage());
+        return false;
+    }
+}
+
+
+/*!
+    Convinience method for sending a synchronous request on-ward.
+    The returnValue delivered via the output parameter.
+    \return True on success, false otherwise
+*/
+bool XQAiwRequest::send(QVariant &returnValue)
+{
+
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::send(retValue)");
+
+    // do request
+    if (sendExecute())
+    {
+        if (currentRequest->isSynchronous())
+        {
+            XQSERVICE_DEBUG_PRINT("XQAiwRequest::set retValue ");
+            // Do not emit requestOk as return value delivered directly
+            returnValue = result; // Copy return value
+            result.clear();
+        }
+        return true;
+    } else
+    {
+        XQSERVICE_DEBUG_PRINT("XQAiwRequest::emit requestError");
+        emit requestError(lastError(), lastErrorMessage());
+        return false;
+    }
+   
+}
+
+/*!
+    Request service application to be launched in embedded mode.
+    \param embedded If set to true, service application will be launched
+                    in embedded mode
+*/
+void XQAiwRequest::setEmbedded(bool embedded)
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::setEmbedded=%d",embedded);
+    currentRequest->setEmbedded(embedded);
+}
+
+/*!
+    Get the value of embedded option of the request.
+    \return True if request is set to launch service application in embedded
+            mode, false otherwise
+*/
+bool XQAiwRequest::isEmbedded() const
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::isEmbedded");
+    return currentRequest->isEmbedded();
+}
+
+/*!
+    Sets service operation. The XQApplicationManager::create() functions for
+    files and URLs set the default operation, but it can be overriden using
+    this function.
+    \param operation Operation to be set to the request.
+*/
+void XQAiwRequest::setOperation(const QString &operation)
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::setOperation");
+    currentRequest->setOperation(operation);
+}
+
+/*!
+    Returns operation attached to the request.
+    \return Operation attached to the request
+*/
+const QString &XQAiwRequest::operation() const
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::operation");
+    return currentRequest->operation();
+}
+
+/*!
+    Sets request as synchronous or asynchronous, based on the \a synchronous value.
+    \param synchronous If set to true, request will be synchronous.
+                       If set to false, request will be asynchronous
+*/
+void XQAiwRequest::setSynchronous(bool synchronous)
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::setSynchronous=%d", synchronous);
+    currentRequest->setSynchronous(synchronous);
+}
+
+/*!
+    Returns the value of the synchronous option.
+    \return True if request is synchronous, false otherwise
+*/
+bool XQAiwRequest::isSynchronous() const
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::isSynchronous");
+    return currentRequest->isSynchronous();
+}
+
+/*!
+    Requests service application to be launched to background initially,
+    or if already running, to go to background.
+    \param background If set to true, service application will be launched
+                      to background
+*/
+void XQAiwRequest::setBackground(bool background )
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::setbackground=%d", background);
+    currentRequest->setBackground(background);
+}
+
+/*!
+    Returns the value of the background option.
+    \return True if request is set to launch service
+                 application to background
+*/
+bool XQAiwRequest::isBackground() const
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::isBackground");
+    return currentRequest->isBackground();
+}
+
+/*!
+    Used to set additional UI behavior type options to the request.
+    Embedded and background options are handled by their own functions.
+    This function should not be used to implement additional data
+    parameters for operations!
+    \param info UI bahavior type option to be set to the request.
+*/
+void XQAiwRequest::setInfo(const XQRequestInfo &info)
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::setInfo");
+    return currentRequest->setInfo(info);
+}
+
+/*!
+    Returns additional options attached to the request.
+    \return Additional options attached to the request.
+*/
+XQRequestInfo XQAiwRequest::info() const
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::info");
+    return currentRequest->info();
+}
+
+
+
+const QVariant &XQAiwRequest::results() const
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::results");
+    return result;
+}
+
+
+void XQAiwRequest::sendFromAction(bool checked)
+{
+    Q_UNUSED(checked);
+    
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::sendFromAction");
+    
+    emit triggered(); // Last chance to setup request parameters
+
+    // do request
+    if (sendExecute())
+    {
+        if (isSynchronous())
+        {
+            emit requestOk(result);
+            result.clear();
+        }
+    } else
+    {
+        emit requestError(lastError(), lastErrorMessage());
+    }
+}
+
+bool XQAiwRequest::sendExecute()
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::sendExecute>>>");
+
+    QStringList list;
+    bool res = true;
+    if (!isSynchronous() && !completeSignalConnected)
+    {
+        // Set async request signals once
+        XQSERVICE_DEBUG_PRINT("request::async send");
+        connect(currentRequest, SIGNAL(requestOk(const QVariant&)), this, SLOT(handleAsyncResponse(const QVariant&)));
+        completeSignalConnected = true;
+    }
+    if (!errorSignalConnected)
+    {
+        // Connect always error signal  once
+        connect(currentRequest, SIGNAL(requestError(int,const QString&)), this, SLOT(handleAsyncError(int)));
+        errorSignalConnected = true;
+    }
+    
+    XQSERVICE_DEBUG_PRINT("request::send>>>");
+    res = currentRequest->send(result);  // Result is valid for sync request only    
+    XQSERVICE_DEBUG_PRINT("request::send: %d<<<", res);
+    
+    errorCode = currentRequest->lastError(); // ask always
+    if (errorCode || !res)
+    {
+        res = false;
+    }
+    
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::sendExecute: %d<<<", res);
+    
+    return res;
+
+}
+
+
+
+void XQAiwRequest::handleAsyncResponse(const QVariant& value)
+{
+    XQSERVICE_DEBUG_PRINT("XQAiwRequest::handleAsyncResponse");
+    emit requestOk(value);
+}
+
+void XQAiwRequest::handleAsyncError(int err)
+{
+   XQSERVICE_DEBUG_PRINT("XQAiwRequest::handleAsyncError");
+   errorCode = err;
+   emit requestError(lastError(), lastErrorMessage());
+}