qthighway/xqservice/src/xqservicerequest.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 27 May 2010 13:42:11 +0300
changeset 8 71781823f776
parent 4 90517678cc4f
child 19 46686fb6258c
permissions -rw-r--r--
Revision: 201019 Kit: 2010121

/*
* 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 : public XQServiceRequestCompletedAsync
{
public:
    XQServiceRequest_Private(XQServiceRequest* parent)
        : m_Synchronous(true), m_Parent(parent),serviceManager(NULL)
    {    
        XQSERVICE_DEBUG_PRINT("XQServiceRequest_Private::XQServiceRequest_Private(1)");
        
    };

    XQServiceRequest_Private(const QString& service, 
                             const QString& message, 
                             const bool &synchronous, 
                             XQServiceRequest* parent)
        : m_Service(service), m_Message(message), m_Synchronous(synchronous), m_Parent(parent),serviceManager(NULL)
    {    
        XQSERVICE_DEBUG_PRINT("XQServiceRequest_Private::XQServiceRequest_Private(2)");
    };

    XQServiceRequest_Private(const XQAiwInterfaceDescriptor &descriptor, 
                             const QString& message, 
                             const bool &synchronous, 
                            XQServiceRequest* parent)
            : m_Message(message), m_Synchronous(synchronous), m_Parent(parent),serviceManager(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)
        m_Service = descriptor.serviceName() + "." + descriptor.interfaceName();
        XQSERVICE_DEBUG_PRINT("XQServiceRequest_Private(3)::service=%s", qPrintable(m_Service));

        // Remember the descriptor
        m_RequestUtil.mDescriptor = descriptor; 
    };
    
    ~XQServiceRequest_Private();
    // from XQServiceRequestCompletedAsync
    void requestCompletedAsync(const QVariant &retValue);
    void requestErrorAsync(int err);
    
    QList<QVariant> m_arguments;
    QString m_Service;
    QString m_Message;
    bool m_Synchronous;
    XQServiceRequest* m_Parent;
    XQRequestUtil m_RequestUtil;
    XQServiceManager* serviceManager;
    QString m_uniqueChannelName;
    
};

XQServiceRequest_Private::~XQServiceRequest_Private()
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest_Private::~XQServiceRequest_Private");
    delete serviceManager;
};

void XQServiceRequest_Private::requestCompletedAsync(const QVariant &retValue)
{    
    XQSERVICE_DEBUG_PRINT("XQServiceRequest_Private::requestCompletedAsync");
    emit m_Parent->requestCompleted(retValue);
}

void XQServiceRequest_Private::requestErrorAsync(int err)
{    
    XQSERVICE_DEBUG_PRINT("XQServiceRequest_Private::requestErrorAsync");
    emit m_Parent->requestError(err);
}

/*!
  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)");
    m_data = 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.
*/
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);
    m_data = new XQServiceRequest_Private(service,message,synchronous,this);
}

/*!
  Copy constructor. Any data previously written to the \a orig
  service will be in the copy.
*/
XQServiceRequest::XQServiceRequest(const XQServiceRequest& orig)
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::XQServiceRequest(3)");
    m_data = new XQServiceRequest_Private(orig.m_data->m_Service,orig.m_data->m_Message,orig.m_data->m_Synchronous,this);
    m_data->m_arguments = orig.m_data->m_arguments;
}

/*!
  Construct a service request by service descriptor which contains exact details of the service and interface.
  a \a service when send() is called. The service may be written
  prior to the calls.
*/
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);
    m_data = 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;

    m_data->m_Service = orig.m_data->m_Service;
    m_data->m_Message = orig.m_data->m_Message;
    m_data->m_arguments = orig.m_data->m_arguments;
    m_data->m_RequestUtil = orig.m_data->m_RequestUtil;

    return *this;
}

/*!
  Destructs the service request. Unlike QtopiaIpcEnvelope, the
  request is not automatically sent.
*/
XQServiceRequest::~XQServiceRequest()
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::~XQServiceRequest %s", qPrintable(m_data->m_uniqueChannelName));
    XQServiceAdaptor::cancelPendingSend(m_data->m_uniqueChannelName);
    delete m_data;
}

/*!
  Returns true if either the service() or message() is not set.

  \sa service(), message()
 */
bool XQServiceRequest::isNull() const
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::isNull");
    bool ret = m_data->m_Service.isEmpty() || m_data->m_Service.isNull() || m_data->m_Message.isNull();
	XQSERVICE_DEBUG_PRINT("m_data->m_Service.isEmpty() = %d", m_data->m_Service.isEmpty());
	XQSERVICE_DEBUG_PRINT("m_data->m_Service.isNull() = %d", m_data->m_Service.isNull());
	XQSERVICE_DEBUG_PRINT("m_data->m_Message.isNull() = %d", m_data->m_Message.isNull());
	XQSERVICE_DEBUG_PRINT("return %d", ret);
	return ret;
}

bool XQServiceRequest::isSynchronous() const
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::isSynchronous");
    return m_data->m_Synchronous;
}

void XQServiceRequest::setSynchronous(const bool& synchronous)
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::setSynchronous");
    m_data->m_Synchronous = synchronous;
}
/*!
  \fn QString XQServiceRequest::send()
  Sends the request. Returns false if there was no application that could
  service the request.
*/
bool XQServiceRequest::send()
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::send(1)");
    QVariant retValue;
    return send(retValue);
}

/*!
  \fn QString XQServiceRequest::send()
  Sends the request. Returns false if there was no application that could
  service the request.
*/
bool XQServiceRequest::send(QVariant& retData)
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::send(2)");
    if (isNull()) {
        XQSERVICE_DEBUG_PRINT("Request is null");
        return false;
    }
    
    if (m_data->m_Service.isNull())
        return false;

    // Handle sharable file argument(s), if any
    if (!handleSharableFileArgs())
    {
        XQService::serviceThreadData()->setLatestError(XQService::EArgumentError);
        return false;
    }
    
    m_data->m_RequestUtil.setSynchronous(m_data->m_Synchronous); // Ensure option is set !
    m_data->m_RequestUtil.mOperation = m_data->m_Message;  // Save the operation name for startup
    
    // !!!
    // Add the info as extra argument to the request
    // This shall be removed by the server
    // !!!
    addArg(qVariantFromValue(m_data->m_RequestUtil.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)m_data;
    m_data->m_uniqueChannelName = QString("%1:").arg(handle) + m_data->m_Service;
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::send(2):uniqueChannel=%s", qPrintable(m_data->m_uniqueChannelName));
    return XQServiceAdaptor::send(m_data->m_uniqueChannelName,  message(), m_data->m_arguments, retData, m_data->m_Synchronous,m_data,
                                 (const void *)&m_data->m_RequestUtil);
}
/*!
  Sets the \a service to which the request will be sent.

  \sa service()
 */
void XQServiceRequest::setService(const QString& service)
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::setService");
    XQSERVICE_DEBUG_PRINT("service: %s", qPrintable(service));
    m_data->m_Service = service;
    m_data->m_arguments.clear();
}

/*!
  \fn QString XQServiceRequest::service() const

  Returns the service to which this request will be sent.

  \sa setService()
*/
QString XQServiceRequest::service() const
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::service");
    XQSERVICE_DEBUG_PRINT("service: %s", qPrintable(m_data->m_Service));
    return m_data->m_Service;
}

/*!
    Sets the \a message to be sent to the service.

    \sa message()
*/
void XQServiceRequest::setMessage(const QString& message)
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::setMessage");
    XQSERVICE_DEBUG_PRINT("message: %s", qPrintable(message));
    m_data->m_Message = message;
    m_data->m_arguments.clear();
}

QString XQServiceRequest::message() const
{ 
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::message");
    XQSERVICE_DEBUG_PRINT("message: %s", qPrintable(m_data->m_Message));
    return m_data->m_Message;
}

const QList<QVariant> &XQServiceRequest::arguments() const 
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::arguments");
    return m_data->m_arguments; 
}

void XQServiceRequest::setArguments(const QList<QVariant> &arguments)
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::setArguments");
    m_data->m_arguments = arguments;
}

int XQServiceRequest::latestError()
    {
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::latestError");
    return XQServiceAdaptor::latestError();
    }

void XQServiceRequest::setInfo(const XQRequestInfo &info)
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::setInfo");
    m_data->m_RequestUtil.mInfo = info;
}

XQRequestInfo XQServiceRequest::info() const
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::info");
    return m_data->m_RequestUtil.mInfo;
}
    
/*!
  \fn QString XQServiceRequest::message() const

  Returns the message of the request.

  \sa setMessage()
*/

/*!
    \fn const QList<QVariant> &XQServiceRequest::arguments() const

    Returns the complete list of arguments for this service request.
*/

/*!
    \fn void XQServiceRequest::setArguments(const QList<QVariant> &arguments)

    Sets the complete list of \a arguments for this service request.
*/

/*!
    \fn XQServiceRequest &XQServiceRequest::operator<< (const T &var)

    Adds \a var to the list of arguments for this service request.
*/

/*!
    \fn XQServiceRequest &XQServiceRequest::operator<< (const char *var)

    Adds \a var to the list of arguments for this service request.
*/

/*!
    \fn void XQServiceRequest::addArg(const QVariant& var)

    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.
*/

/*!
    \internal
*/
void XQServiceRequest::addArg(const QVariant& v)
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::addArg %s,%d", v.typeName());
    XQSERVICE_DEBUG_PRINT("v: %s", qPrintable(v.toString()));
    m_data->m_arguments.append(v);
}


/*!
    \fn void XQServiceRequest::handleSharableFileArg()

    Picks the XQSharableFile argument, if any, into the request util
    By this way scan parameter list only once.
*/

/*!
    \internal
*/
bool XQServiceRequest::handleSharableFileArgs()
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::handleSharableFile");

    bool ret = true;
    m_data->m_RequestUtil.mSharableFileArgs.clear();
    
    for(int i=0; i < m_data->m_arguments.size(); i++)
    {
        if (QString(m_data->m_arguments[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 = m_data->m_arguments[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 (m_data->m_RequestUtil.mSharableFileArgs.count() > 0)
            {
                XQSERVICE_DEBUG_PRINT("\t Too many sharable files");
                ret = false;
                break;
            }
            m_data->m_RequestUtil.mSharableFileArgs.append(file);
            XQSERVICE_DEBUG_PRINT("XQServiceRequest::sharable file added");
        }
    }

    if (!ret)
    {
        m_data->m_RequestUtil.mSharableFileArgs.clear();
    }

    return ret;
}


/*!
    \internal
*/
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.m_data->m_arguments;

    delete buffer;
    return ret;
}
/*!
    \internal
*/
void XQServiceRequest::deserializeArguments(XQServiceRequest &action,
        const QByteArray &data)
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::deserializeArguments");
    QDataStream stream(data);
    stream >> action.m_data->m_arguments;
}

/*!
    \internal
    \fn void XQServiceRequest::serialize(Stream &stream) const
*/
template <typename Stream> void XQServiceRequest::serialize(Stream &stream) const
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::serialize");
    stream << m_data->m_arguments;
    stream << m_data->m_Service;
    stream << m_data->m_Message;
    stream << m_data->m_Synchronous;
}

/*!
    \internal
    \fn void XQServiceRequest::deserialize(Stream &stream)
*/
template <typename Stream> void XQServiceRequest::deserialize(Stream &stream)
{
    XQSERVICE_DEBUG_PRINT("XQServiceRequest::deserialize");
    stream >> m_data->m_arguments;
    stream >> m_data->m_Service;
    stream >> m_data->m_Message;
    stream >> m_data->m_Synchronous;
}

Q_IMPLEMENT_USER_METATYPE(XQServiceRequest)