qthighway/xqservice/src/xqserviceadaptor.cpp
branchRCL_3
changeset 9 5d007b20cfd0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qthighway/xqservice/src/xqserviceadaptor.cpp	Tue Aug 31 16:02:37 2010 +0300
@@ -0,0 +1,982 @@
+/*
+* 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 "xqserviceglobal.h"
+#include "xqserviceadaptor.h"
+#include "xqservicechannel.h"
+#include "xqservicethreaddata.h"
+#include "xqserviceipcclient.h"
+
+#include <xqserviceutil.h>
+#include <xqrequestutil.h>
+#include <qmetaobject.h>
+#include <QMap>
+#include <QDataStream>
+#include <qatomic.h>
+#include <QDebug>
+#include <QVarLengthArray>
+#include <e32err.h>
+#include <xqsharablefile.h>
+
+/*!
+    \class XQServiceAdaptor
+    \inpublicgroup QtBaseModule
+
+    \ingroup ipc
+    \brief The XQServiceAdaptor class provides an interface to messages on a XQService IPC channel which simplifies remote signal and slot invocations.
+
+    Using this class, it is very easy to convert a signal emission into an IPC
+    message on a channel, and to convert an IPC message on a channel into a
+    slot invocation.  In the following example, when the signal \c{valueChanged(int)}
+    is emitted from the object \c source, the IPC message \c{changeValue(int)} will
+    be sent on the channel \c{QPE/Foo}:
+
+    \code
+    XQServiceAdaptor *adaptor = new XQServiceAdaptor("QPE/Foo");
+    XQServiceAdaptor::connect
+        (source, SIGNAL(valueChanged(int)), adaptor, MESSAGE(changeValue(int)));
+    \endcode
+
+    Note that we use XQServiceAdaptor::connect() to connect the signal to the
+    IPC message, not QObject::connect().  A common error is to use \c{connect()}
+    without qualifying it with \c{XQServiceAdaptor::} and picking up
+    QObject::connect() by mistake.
+
+    On the server side of an IPC protocol, the \c{changeValue(int)} message can
+    be connected to the slot \c{setValue()} on \c dest:
+
+    \code
+    XQServiceAdaptor *adaptor = new XQServiceAdaptor("QPE/Foo");
+    XQServiceAdaptor::connect
+        (adaptor, MESSAGE(changeValue(int)), dest, SLOT(setValue(int)));
+    \endcode
+
+    Now, whenever the client emits the \c{valueChanged(int)} signal, the
+    \c{setValue(int)} slot will be automatically invoked on the server side,
+    with the \c int parameter passed as its argument.
+
+    Only certain parameter types can be passed across an IPC boundary in this fashion.
+    The type must be visible to QVariant as a meta-type.  Many simple built-in
+    types are already visible; for user-defined types, use Q_DECLARE_METATYPE()
+    and qRegisterMetaTypeStreamOperators().
+
+    \sa XQServiceChannel
+*/
+
+class XQServiceAdaptorChannel : public XQServiceChannel
+{
+    Q_OBJECT
+public:
+    XQServiceAdaptorChannel(const QString& channel, XQServiceAdaptor *adapt)
+        : XQServiceChannel(channel, true, adapt), adaptor(adapt) 
+    {
+        XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::XQServiceAdaptorChannel");
+    }
+    
+    ~XQServiceAdaptorChannel() 
+    {
+        XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::~XQServiceAdaptorChannel");
+    }
+
+    QVariant receive(const QString& msg, const QByteArray &data, const XQSharableFile &sf);
+    void commandReceive(const XQServiceCommand cmd);
+
+private slots:
+    
+private:
+    XQServiceAdaptor *adaptor;
+};
+
+QVariant XQServiceAdaptorChannel::receive(const QString& msg, const QByteArray &data, const XQSharableFile &sf)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::receive");
+    return adaptor->received(msg, data, sf);
+}
+
+void XQServiceAdaptorChannel::commandReceive(const XQServiceCommand cmd)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::commandReceive %d", cmd);
+    switch (cmd)
+    {
+        case ReturnValueDelivered:
+            emit adaptor->returnValueDelivered() ;
+            break;
+            
+        case ClientDisconnected:
+            emit adaptor->clientDisconnected() ;
+            break;
+            
+        default:
+            XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::unhandled command %d", cmd);
+        break;
+    }
+}
+
+class XQServiceAdaptorSignalInfo
+{
+public:
+    QObject *sender;
+    int signalIndex;
+    int destroyIndex;
+    QString message;
+    int *types;
+    int numArgs;
+};
+
+class XQServiceAdaptorSlotInfo
+{
+public:
+    ~XQServiceAdaptorSlotInfo()
+    {
+        XQSERVICE_DEBUG_PRINT("XQServiceAdaptorSlotInfo::~XQServiceAdaptorSlotInfo");
+        qFree(types);
+    }
+
+    QObject *receiver;
+    int memberIndex;
+    bool destroyed;
+    int returnType;
+    int *types;
+    int numArgs;
+};
+
+class XQServiceAdaptorPrivate : public QObject
+{
+    // Do not put Q_OBJECT here.
+public:
+    XQServiceAdaptorPrivate(XQServiceAdaptor *obj, const QString& chan);
+    ~XQServiceAdaptorPrivate();
+
+    QAtomicInt ref;
+    XQServiceAdaptor *parent;
+    QString channelName;
+    bool connected;
+    const QMetaObject *publishedTo;
+    QMultiMap<QString, XQServiceAdaptorSlotInfo *> invokers;
+    QList<XQServiceAdaptorSignalInfo *> signalList;
+    int slotIndex;
+
+    static const int QVariantId = -243;
+    static int *connectionTypes(const QByteArray& member, int& nargs);
+    static int typeFromName(const QByteArray& name);
+
+protected:
+    int qt_metacall(QMetaObject::Call c, int id, void **a);
+};
+
+XQServiceAdaptorPrivate::XQServiceAdaptorPrivate(XQServiceAdaptor *obj, const QString& chan)
+    : ref(1), channelName(chan)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::XQServiceAdaptorPrivate");
+    parent = obj;
+    connected = false;
+    publishedTo = 0;
+
+    // Fake slots start at this index in the QMetaObject.
+    slotIndex = staticMetaObject.methodCount();
+}
+
+XQServiceAdaptorPrivate::~XQServiceAdaptorPrivate()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::~XQServiceAdaptorPrivate");
+    qDeleteAll(invokers);
+
+    // Disconnect all of the signals associated with this adaptor.
+    int index = slotIndex;
+    XQSERVICE_DEBUG_PRINT("index: %d", index);
+    foreach (XQServiceAdaptorSignalInfo *info, signalList) {
+        XQSERVICE_DEBUG_PRINT("info->signalIndex: %d", info->signalIndex);
+        if (info->signalIndex >= 0) {
+            QMetaObject::disconnect(info->sender, info->signalIndex,
+                                    this, index);
+        }
+        XQSERVICE_DEBUG_PRINT("info->destroyIndex: %d", info->destroyIndex);
+        if (info->destroyIndex >= 0) {
+            QMetaObject::disconnect(info->sender, info->destroyIndex,
+                                    this, index + 1);
+        }
+        qFree(info->types);
+        delete info;
+        index += 2;
+    }
+}
+
+// Get the QVariant type number for a type name.
+int XQServiceAdaptorPrivate::typeFromName( const QByteArray& type )
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::typeFromName");
+    XQSERVICE_DEBUG_PRINT("type: %s", type.constData());
+    if (type.endsWith('*')){
+        XQSERVICE_DEBUG_PRINT("Pointer");
+        return QMetaType::VoidStar;
+    }
+    else if ( type.size() == 0 || type == "void" ){
+        XQSERVICE_DEBUG_PRINT("Void");
+        return QMetaType::Void;
+    }
+    else if ( type == "QVariant" ){
+        XQSERVICE_DEBUG_PRINT("QVariant");
+        return XQServiceAdaptorPrivate::QVariantId;
+    }
+    int id = QMetaType::type( type.constData() );
+    XQSERVICE_DEBUG_PRINT("id: %d", id);
+    if ( id != (int)QMetaType::Void )
+        return id;
+    return QVariant::nameToType(type);
+}
+
+// Returns the connection types associated with a signal or slot member.
+int *XQServiceAdaptorPrivate::connectionTypes( const QByteArray& member, int& nargs )
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::connectionTypes");
+    XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+    // Based on Qt's internal queuedConnectionTypes function.
+    nargs = 0;
+    int *types = 0;
+    const char *s = member.constData();
+    while (*s != '\0' && *s != '(') { ++s; }
+    if ( *s == '\0' )
+        return 0;
+    ++s;
+    const char *e = s;
+    while (*e != ')') {
+        ++e;
+        if (*e == ')' || *e == ',')
+            ++nargs;
+    }
+
+    types = (int *) qMalloc((nargs+1)*sizeof(int));
+    types[nargs] = 0;
+    for (int n = 0; n < nargs; ++n) {
+        e = s;
+        while (*s != ',' && *s != ')')
+            ++s;
+        QByteArray type(e, s-e);
+        ++s;
+
+        types[n] = typeFromName(type);
+        if (!types[n]) {
+            XQSERVICE_WARNING_PRINT("XQServiceAdaptorPrivate::connectionTypes: Cannot marshal arguments of type '%s'", type.constData());
+            qFree(types);
+            return 0;
+        }
+    }
+    XQSERVICE_DEBUG_PRINT("types: %d", types);
+    return types;
+}
+
+int XQServiceAdaptorPrivate::qt_metacall(QMetaObject::Call c, int id, void **a)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::qt_metacall");
+    id = QObject::qt_metacall(c, id, a);
+    XQSERVICE_DEBUG_PRINT("id: %d", id);
+    if (id < 0)
+        return id;
+    if (c == QMetaObject::InvokeMetaMethod) {
+        XQSERVICE_DEBUG_PRINT("InvokeMetaMethod");
+        // Each signal that we have intercepted has two fake slots
+        // associated with it.  The first is the activation slot.
+        // The second is the destroyed() slot for the signal's object.
+        if (id < signalList.size() * 2) {
+            XQServiceAdaptorSignalInfo *info = signalList[id / 2];
+            if ((id % 2) == 0) {
+                // The signal we are interested in has been activated.
+                if (info->types) {
+                    XQSERVICE_DEBUG_PRINT("Signal has been activated");
+                    QList<QVariant> args;
+                    XQSERVICE_DEBUG_PRINT("info->numArgs: %d", info->numArgs);
+                    for (int i = 0; i < info->numArgs; ++i) {
+                        if (info->types[i] != XQServiceAdaptorPrivate::QVariantId) {
+                            QVariant arg(info->types[i], a[i + 1]);
+                            XQSERVICE_DEBUG_PRINT("arg: %s", qPrintable(arg.toString()));
+                            args.append(arg);
+                        } else {
+                            args.append(*((const QVariant *)(a[i + 1])));
+                        }
+                    }
+                    //TODO: CHECK HERE
+                    QVariant retValue;
+                    parent->sendMessage(info->message, args,retValue);
+                }
+            } else {
+                XQSERVICE_DEBUG_PRINT("Sender has been destroyed");
+                // The sender has been destroyed.  Clear the signal indices
+                // so that we don't try to do a manual disconnect when our
+                // own destructor is called.
+                info->signalIndex = -1;
+                info->destroyIndex = -1;
+            }
+        }
+        id -= signalList.size() * 2;
+    }
+    XQSERVICE_DEBUG_PRINT("id: %d", id);
+    return id;
+}
+
+/*!
+    Construct a Qt Extended IPC message object for \a channel and attach it to \a parent.
+    If \a channel is empty, then messages are taken from the application's
+    \c{appMessage} channel.
+*/
+XQServiceAdaptor::XQServiceAdaptor(const QString& channel, QObject *parent)
+    : QObject(parent)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::XQServiceAdaptor");
+    d = new XQServiceAdaptorPrivate(this, channel);
+}
+
+/*!
+*/
+XQServiceAdaptor::~XQServiceAdaptor()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::~XQServiceAdaptor");
+    if (!d->ref.deref())
+        delete d;
+    d = 0;
+}
+
+/*!
+    Returns the name of the channel that this adaptor is associated with.
+*/
+QString XQServiceAdaptor::channel() const
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::channel");
+    XQSERVICE_DEBUG_PRINT("d->channelName: %s", qPrintable(d->channelName));
+    return d->channelName;
+}
+
+/*!
+    Connects \a signal on \a sender to \a member on \a receiver.  Returns true
+    if the receiveion was possible; otherwise returns false.
+
+    If either \a sender or \a receiver are instances of
+    XQServiceAdaptor, this function will arrange for the signal
+    to be delivered over a Qt Extended IPC channel.  If both \a sender and
+    \a receiver are local, this function is identical
+    to QObject::connect().
+
+    If the same signal is connected to same slot multiple times,
+    then signal delivery will happen that many times.
+
+    \sa XQServiceAdaptor::ChannelSelector
+*/
+bool XQServiceAdaptor::connect(QObject *sender, const QByteArray& signal,
+                          QObject *receiver, const QByteArray& member)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::connect");
+    XQSERVICE_DEBUG_PRINT("signal: %s", signal.constData());
+    XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+    XQServiceAdaptor *senderProxy;
+    XQServiceAdaptor *receiverProxy;
+
+    // Bail out if the parameters are invalid.
+    if (!sender || signal.isEmpty() || !receiver || member.isEmpty()){
+        XQSERVICE_DEBUG_PRINT("Parameters are invalid");
+        return false;
+    }
+
+    // Resolve the objects to find the remote proxies.
+    senderProxy = qobject_cast<XQServiceAdaptor *>(sender);
+    receiverProxy = qobject_cast<XQServiceAdaptor *>(receiver);
+
+    // Remove proxies if the signal or member is not tagged with MESSAGE().
+    if (!member.startsWith(QMESSAGE_CODE + '0')){
+        XQSERVICE_DEBUG_PRINT("No received proxy");
+        receiverProxy = 0;
+    }
+    if (!signal.startsWith(QMESSAGE_CODE + '0')){
+        XQSERVICE_DEBUG_PRINT("No sender proxy");
+        senderProxy = 0;
+    }
+
+    // If neither has a proxy, then use a local connect.
+    if (!senderProxy && !receiverProxy){
+        XQSERVICE_DEBUG_PRINT("Local connect");
+        return QObject::connect(sender, signal, receiver, member);
+    }
+
+    // If both are still remote proxies, then fail the request.
+    if (senderProxy && receiverProxy) {
+        XQSERVICE_WARNING_PRINT("XQServiceAdaptor::connect: cannot connect MESSAGE() to MESSAGE()");
+        return false;
+    }
+
+    // Determine which direction the connect needs to happen in.
+    if (receiverProxy) {
+        XQSERVICE_DEBUG_PRINT("Connecting a local signal to a remote slot");
+        // Connecting a local signal to a remote slot.
+        return receiverProxy->connectLocalToRemote(sender, signal, member);
+    } else {
+        XQSERVICE_DEBUG_PRINT("Connecting a remote signal to a local slot");
+        // Connecting a remote signal to a local slot.
+        return senderProxy->connectRemoteToLocal(signal, receiver, member);
+    }
+}
+
+/*!
+    Publishes the signal or slot called \a member on this object on
+    the Qt Extended IPC channel represented by this XQServiceAdaptor.
+
+    If \a member is a slot, then whenever an application sends a
+    message to the channel with that name, the system will arrange
+    for the slot to be invoked.
+
+    If \a member is a signal, then whenever this object emits that
+    signal, the system will arrange for a message with that name to
+    be sent on the channel.
+
+    Returns false if \a member does not refer to a valid signal or slot.
+
+    \sa publishAll()
+*/
+bool XQServiceAdaptor::publish(const QByteArray& member)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::publish");
+    XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+    // '1' is QSLOT_CODE in Qt 4.4 and below,
+    // '5' is QSLOT_CODE in Qt 4.5 and higher.
+    if (member.size() >= 1 && (member[0] == '1' || member[0] == '5')) {
+        XQSERVICE_DEBUG_PRINT("Exporting a slot");
+        // Exporting a slot.
+        return connectRemoteToLocal("3" + member.mid(1), this, member);
+    } else {
+        XQSERVICE_DEBUG_PRINT("Exporting a sigal");
+        // Exporting a signal.
+        return connectLocalToRemote(this, member, member);
+    }
+}
+
+/*!
+    \enum XQServiceAdaptor::PublishType
+    Type of members to publish via XQServiceAdaptor.
+
+    \value Signals Publish only signals.
+    \value Slots Publish only public slots.
+    \value SignalsAndSlots Publish both signals and public slots.
+*/
+
+/*!
+    Publishes all signals or public slots on this object within subclasses of
+    XQServiceAdaptor.  This is typically called from a subclass constructor.
+    The \a type indicates if all signals, all public slots, or both, should
+    be published.  Private and protected slots will never be published.
+
+    \sa publish()
+*/
+void XQServiceAdaptor::publishAll(XQServiceAdaptor::PublishType type)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::publishAll(1)");
+    publishAll(this,XQServiceAdaptor::staticMetaObject.methodCount(),type);
+}
+
+void XQServiceAdaptor::publishAll(QObject* object,int metCount, XQServiceAdaptor::PublishType type)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::publishAll(2)");
+    XQSERVICE_DEBUG_PRINT("metCount: %d", metCount);
+    const QMetaObject *meta = object->metaObject();
+    if (meta != d->publishedTo) {
+        int count = meta->methodCount();
+        XQSERVICE_DEBUG_PRINT("count: %d", count);
+        int index;
+        if (d->publishedTo)
+            index = d->publishedTo->methodCount();
+        else
+            index = metCount;
+        XQSERVICE_DEBUG_PRINT("index: %d", index);
+        for (; index < count; ++index) {
+
+            QMetaMethod method = meta->method(index);
+            if (method.methodType() == QMetaMethod::Slot &&
+                 method.access() == QMetaMethod::Public &&
+                 (type == Slots || type == SignalsAndSlots)) {
+                QByteArray name = method.signature();
+                XQSERVICE_DEBUG_PRINT("name: %s", name.constData());
+                XQSERVICE_DEBUG_PRINT("connectRemoteToLocal");
+                connectRemoteToLocal("3" + name, object, "1" + name);
+            } else if (method.methodType() == QMetaMethod::Signal &&
+                        (type == Signals || type == SignalsAndSlots)) {
+                QByteArray name = method.signature();
+                XQSERVICE_DEBUG_PRINT("name: %s", name.constData());
+                XQSERVICE_DEBUG_PRINT("connectLocalToRemote");
+                connectLocalToRemote(object, "2" + name, "3" + name);
+            }
+        }
+        d->publishedTo = meta;
+    }
+}
+
+/*!
+    Sends a message on the Qt Extended IPC channel which will cause the invocation
+    of the single-argument \a member on receiving objects, with the
+    argument \a arg1.
+*/
+bool XQServiceAdaptor::send(const QByteArray& member, const QVariant &arg1, QVariant &retData)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(1)");
+    XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+    XQSERVICE_DEBUG_PRINT("arg1: %s", qPrintable(arg1.toString()));
+    QList<QVariant> args;
+    args.append(arg1);
+    return sendMessage(memberToMessage(member), args, retData);
+}
+
+/*!
+    Sends a message on the Qt Extended IPC channel which will cause the invocation
+    of the double-argument \a member on receiving objects, with the
+    arguments \a arg1 and \a arg2.
+*/
+bool XQServiceAdaptor::send(const QByteArray& member, const QVariant &arg1, const QVariant &arg2, QVariant &retData)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(2)");
+    XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+    XQSERVICE_DEBUG_PRINT("arg1: %s, arg2: %s", qPrintable(arg1.toString()), qPrintable(arg2.toString()));
+    QList<QVariant> args;
+    args.append(arg1);
+    args.append(arg2);
+    return sendMessage(memberToMessage(member), args, retData);
+}
+
+/*!
+    Sends a message on the Qt Extended IPC channel which will cause the invocation
+    of the triple-argument \a member on receiving objects, with the
+    arguments \a arg1, \a arg2, and \a arg3.
+*/
+bool XQServiceAdaptor::send(const QByteArray& member, const QVariant &arg1,
+                       const QVariant &arg2, const QVariant &arg3, QVariant &retData)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(3)");
+    XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+    XQSERVICE_DEBUG_PRINT("arg1: %s, arg2: %s, arg3: %s", qPrintable(arg1.toString()), qPrintable(arg2.toString()), qPrintable(arg3.toString()));
+    QList<QVariant> args;
+    args.append(arg1);
+    args.append(arg2);
+    args.append(arg3);
+    return sendMessage(memberToMessage(member), args, retData);
+}
+
+/*!
+    Sends a message on the Qt Extended IPC channel which will cause the invocation
+    of the multi-argument \a member on receiving objects, with the
+    argument list \a args.
+*/
+bool XQServiceAdaptor::send(const QByteArray& member, const QList<QVariant>& args, QVariant &retData)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(4)");
+    XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+    for(int i=0;i<args.size();++i){
+        XQSERVICE_DEBUG_PRINT("args[%d]: %s", i, qPrintable(args[i].toString()));
+    }
+    return sendMessage(memberToMessage(member), args, retData);
+}
+
+/*!
+    Returns true if the message on the Qt Extended IPC channel corresponding to \a signal
+    has been connected to a local slot; otherwise returns false.
+*/
+bool XQServiceAdaptor::isConnected(const QByteArray& signal)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::isConnected");
+    XQSERVICE_DEBUG_PRINT("signal: %s", signal.constData());
+    return d->invokers.contains(memberToMessage(signal));
+}
+
+/*!
+    Converts a signal or slot \a member name into a Qt Extended IPC message name.
+    The default implementation strips the signal or slot prefix number
+    from \a member and then normalizes the name to convert types
+    such as \c{const QString&} into QString.
+
+    \sa QMetaObject::normalizedSignature()
+*/
+QString XQServiceAdaptor::memberToMessage(const QByteArray& member)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::memberToMessage");
+    XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+    if (member.size() >= 1 && member[0] >= '0' && member[0] <= '9') {
+        return QString::fromLatin1
+            (QMetaObject::normalizedSignature(member.constData() + 1));
+    } else {
+        return QString::fromLatin1(member.data(), member.size());
+    }
+}
+
+QVariant XQServiceAdaptor::received(const QString& msg, const QByteArray& data, const XQSharableFile &sf)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::received");
+    XQSERVICE_DEBUG_PRINT("\tmsg: %s", qPrintable(msg));
+    XQSERVICE_DEBUG_PRINT("\tdata: %s", data.constData());
+    QVariant returnValue;
+    bool found = false;
+    // Increase the reference count on the private data just
+    // in case the XQServiceAdaptor is deleted by one of the slots.
+    XQServiceAdaptorPrivate *priv = d;
+    priv->ref.ref();
+
+    // Iterate through the slots for the message and invoke them.
+    QMultiMap<QString, XQServiceAdaptorSlotInfo *>::ConstIterator iter;
+    for (iter = priv->invokers.find(msg);
+         iter != priv->invokers.end() && iter.key() == msg; ++iter) {
+        XQServiceAdaptorSlotInfo *info = iter.value();
+        if (info->destroyed){
+            XQSERVICE_DEBUG_PRINT("\tDestroyed");
+            continue;
+        }
+
+        // Convert "data" into a set of arguments suitable for qt_metacall.
+        QDataStream stream(data);
+        QList<QVariant> args;
+        // a[0] is return value (numArgs+1)
+        QVarLengthArray<void *, 32> a(info->numArgs + 1);
+        
+        XQSERVICE_DEBUG_PRINT("\tinfo->returnType: %d", info->returnType);
+        
+        if (info->returnType != (int)QVariant::Invalid) {
+            returnValue = QVariant(info->returnType, (const void *)0);
+            a[0] = returnValue.data();
+        } else {
+            a[0] = 0;
+        }
+        // Need to pick also the last XQRequestInfo form the stream
+        // That's why iterating up to numArgs+1
+        
+        int reqInfoIndex = info->numArgs;
+
+        
+        for (int arg = 0; arg < info->numArgs+1; ++arg)             
+            {
+            XQSERVICE_DEBUG_PRINT("\tDesserialize argument: %d", arg);
+            if (arg == reqInfoIndex)
+            {
+                // The last argument should be the request index
+                XQSERVICE_DEBUG_PRINT("\tDesserialize XQRequestInfo");
+                QVariant v;
+                stream >> v;
+                XQSERVICE_DEBUG_PRINT("\tXQRequestInfo:QVariant type=%s", v.typeName());
+                if (QString(v.typeName()) == QString("XQRequestInfo"))
+                {
+                    XQRequestInfo info = v.value<XQRequestInfo>();
+                    
+                    //bring foreground or background based on RequestInfo from client side.
+                    bool bg = info.isBackground();
+                    bool fg = info.isForeground();
+                    if (bg && !fg)
+                    {
+                        XQSERVICE_DEBUG_PRINT("\tApply background option");
+                        XQServiceUtil::toBackground(true);
+                    }
+                    else if (fg && !bg)
+                    {
+                        XQSERVICE_DEBUG_PRINT("\tApply foreground option");
+                        XQServiceUtil::toBackground(false);
+                    }
+                    // If both off or both on, do not do anything
+                    
+                    XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(d->channelName);
+                    // Attach to current request before the metacall below !
+                    cl->setRequestInfo(info);
+                }
+            }
+            else if (info->types[arg] == XQServiceAdaptorPrivate::QVariantId)
+            {
+                // We need to handle QVariant specially because we actually
+                // need the type header in this case.
+                QVariant temp;
+                stream >> temp;
+
+                XQSERVICE_DEBUG_PRINT("\tQVariantId:QVariant type=%s", temp.typeName());
+
+                if (QString(temp.typeName()) == QString("XQSharableFile"))
+                {
+                    //apply the patch
+                    if ( sf.isValid())
+                    {
+                        temp = qVariantFromValue( sf );
+                    }
+                }
+
+                args.append(temp);
+                a[arg + 1] = (void *)&(args[arg]);
+            }
+            else {
+                //
+                // The default handling
+                //
+                QVariant temp;
+                stream >> temp;
+                
+                XQSERVICE_DEBUG_PRINT("\tDefault:QVariant type=%s", temp.typeName());
+                
+                if (QString(temp.typeName()) == QString("XQSharableFile"))
+                    {
+                    //apply the patch
+                    if ( sf.isValid())
+                        {
+                        temp = qVariantFromValue( sf );
+                        }
+                    }
+                
+                args.append(temp);
+                a[arg + 1] = (void *)(args[arg].data());
+            }
+        }
+
+        // Invoke the specified slot.
+    #if !defined(QT_NO_EXCEPTIONS)
+        try {
+    #endif
+            XQSERVICE_DEBUG_PRINT("Try to make metacall");
+            info->receiver->qt_metacall
+                (QMetaObject::InvokeMetaMethod, info->memberIndex, a.data());
+            found = true;
+    #if !defined(QT_NO_EXCEPTIONS)
+        } catch (...) {
+        }
+    #endif
+    }
+    if (!found)
+        {
+        XQSERVICE_DEBUG_PRINT("Not found");
+        XQService::serviceThreadData()->setLatestError(XQService::EMessageNotFound);
+        }
+    // Decrease the reference count and delete if necessary.
+    if (!priv->ref.deref())
+        delete priv;
+    
+    XQSERVICE_DEBUG_PRINT("returnValue: %s", qPrintable(returnValue.toString()));
+    return returnValue;
+}
+
+void XQServiceAdaptor::receiverDestroyed()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::receiverDestroyed");
+    // Mark all slot information blocks that match the receiver
+    // as destroyed so that we don't try to invoke them again.
+    QObject *obj = sender();
+    QMultiMap<QString, XQServiceAdaptorSlotInfo *>::Iterator it;
+    for (it = d->invokers.begin(); it != d->invokers.end(); ++it) {
+        if (it.value()->receiver == obj)
+            it.value()->destroyed = true;
+    }
+}
+
+bool XQServiceAdaptor::connectLocalToRemote
+    (QObject *sender, const QByteArray& signal, const QByteArray& member)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::connectLocalToRemote");
+    XQSERVICE_DEBUG_PRINT("sender->objectName(): %s", qPrintable(sender->objectName()));
+    XQSERVICE_DEBUG_PRINT("signal: %s", signal.constData());
+    XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+    XQServiceAdaptorSignalInfo *info = new XQServiceAdaptorSignalInfo();
+    info->sender = sender;
+    info->message = memberToMessage(member);
+
+    // Resolve the signal name on the sender object.
+    if (signal.size() > 0) {
+        if (signal[0] != (QSIGNAL_CODE + '0')) {
+            XQSERVICE_WARNING_PRINT("XQServiceAdaptor: `%s' is not a valid signal specification", signal.constData());
+            delete info;
+            return false;
+        }
+        QByteArray signalName =
+            QMetaObject::normalizedSignature(signal.constData() + 1);
+        info->signalIndex
+            = sender->metaObject()->indexOfSignal(signalName.constData());
+        XQSERVICE_DEBUG_PRINT("info->signalIndex: %d", info->signalIndex);
+        if (info->signalIndex < 0) {
+            XQSERVICE_WARNING_PRINT("XQServiceAdaptor: no such signal: %s::%s",
+                                    sender->metaObject()->className(), signalName.constData());
+            delete info;
+            return false;
+        }
+        info->destroyIndex
+            = sender->metaObject()->indexOfSignal("destroyed()");
+        info->types = XQServiceAdaptorPrivate::connectionTypes
+            (signalName, info->numArgs);
+    } else {
+        XQSERVICE_DEBUG_PRINT("No signal");
+        delete info;
+        return false;
+    }
+
+    // Connect up the signals.
+    int index = d->slotIndex + d->signalList.size() * 2;
+    XQSERVICE_DEBUG_PRINT("index: %d", index);
+    QMetaObject::connect(sender, info->signalIndex, d, index,
+                         Qt::DirectConnection, 0);
+    if (info->destroyIndex >= 0) {
+        QMetaObject::connect(sender, info->destroyIndex, d, index + 1,
+                             Qt::DirectConnection, 0);
+    }
+
+    // Add the signal information to the active list.
+    d->signalList.append(info);
+    return true;
+}
+
+bool XQServiceAdaptor::connectRemoteToLocal
+    (const QByteArray& signal, QObject *receiver, const QByteArray& member)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::connectRemoteToLocal");
+    XQSERVICE_DEBUG_PRINT("signal: %s", signal.constData());
+    XQSERVICE_DEBUG_PRINT("receiver->objectName(): %s", qPrintable(receiver->objectName()));
+    XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
+    // Make sure that we are actively monitoring the channel for messages.
+    if (!d->connected) {
+        XQSERVICE_DEBUG_PRINT("Try to connect to channel");
+        QString chan = d->channelName;
+        // Short-cut the signal emits in XQServiceChannel for greater
+        // performance when dispatching incoming messages.
+        XQServiceAdaptorChannel* adaptorChannel = new XQServiceAdaptorChannel(chan, this);
+        bool ret = adaptorChannel ? adaptorChannel->connectChannel() : false;
+        XQSERVICE_DEBUG_PRINT("ret: %d", ret);
+        if (!ret) {
+            return ret;
+        }
+        d->connected = true;
+    }
+
+    // Create a slot invoker to handle executing the member when necessary.
+    XQServiceAdaptorSlotInfo *info = new XQServiceAdaptorSlotInfo();
+    QByteArray name;
+    if (member.size() > 0 && member[0] >= '0' && member[0] <= '9') {
+        // Strip off the member type code.
+        name = QMetaObject::normalizedSignature(member.constData() + 1);
+    } else {
+        name = QMetaObject::normalizedSignature(member.constData());
+    }
+    info->receiver = receiver;
+    info->returnType = 0;
+    info->types = 0;
+    info->numArgs = 0;
+    info->destroyed = false;
+    if (receiver && name.size() > 0) {
+        info->memberIndex
+            = receiver->metaObject()->indexOfMethod(name.constData());
+        XQSERVICE_DEBUG_PRINT("info->memberIndex: %d", info->memberIndex);
+        if (info->memberIndex != -1) {
+            connect(receiver, SIGNAL(destroyed()), this, SLOT(receiverDestroyed()));
+            QMetaMethod method = receiver->metaObject()->method(info->memberIndex);
+            info->returnType = XQServiceAdaptorPrivate::typeFromName(method.typeName());
+            info->types = XQServiceAdaptorPrivate::connectionTypes(name, info->numArgs);
+            if (!(info->types))
+                info->destroyed = true;
+        } else {
+            XQSERVICE_WARNING_PRINT("XQServiceAdaptor: no such member: %s::%s",
+                                     receiver->metaObject()->className(), name.constData());
+        }
+    } else {
+        info->memberIndex = -1;
+    }
+    if (info->memberIndex == -1) {
+        XQSERVICE_DEBUG_PRINT("No receiver");
+        delete info;
+        return false;
+    }
+    d->invokers.insert(memberToMessage(signal), info);
+    return true;
+}
+
+bool XQServiceAdaptor::sendMessage(const QString& msg, const QList<QVariant>& args, QVariant &retData)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::sendMessage");
+    return send(d->channelName, msg, args, retData);
+}
+
+
+bool XQServiceAdaptor::send(const QString& channel,
+                            const QString& msg, 
+                            const QList<QVariant>& args,
+                            QVariant& retValue,
+                            bool sync,
+                            XQServiceRequestCompletedAsync* rc)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(1). No user data");
+    return send(channel,msg,args,retValue,sync,rc,NULL);
+}
+
+bool XQServiceAdaptor::send(const QString& channel,
+                            const QString& msg, 
+                            const QList<QVariant>& args,
+                            QVariant& retValue,
+                            bool sync,
+                            XQServiceRequestCompletedAsync* rc,
+                            const void *userData)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(2)");
+    XQSERVICE_DEBUG_PRINT("channel: %s, sync: %d", qPrintable(channel), sync);
+    XQSERVICE_DEBUG_PRINT("msg: %s", qPrintable(msg));
+    XQSERVICE_DEBUG_PRINT("userdata: %x",(int)userData);
+    for(int i=0;i<args.size();++i){
+        XQSERVICE_DEBUG_PRINT("args[%d]:type=%s,value=%s", i, args[i].typeName(), qPrintable(args[i].toString()));
+    }
+    if (!sync && !rc) {
+        // Something wrong as no callback given
+        XQService::serviceThreadData()->setLatestError(XQService::EArgumentError);
+        return false;
+    }
+    QByteArray array;
+    QDataStream stream(&array, QIODevice::WriteOnly | QIODevice::Append);
+    QList<QVariant>::ConstIterator iter;
+    for (iter = args.begin(); iter != args.end(); ++iter) {
+        stream << *iter;
+    }
+    // Stream is flushed and closed at this point.
+    return XQServiceChannel::send(channel, msg, array, retValue, sync, rc, userData);
+}
+
+bool XQServiceAdaptor::cancelPendingSend(const QString& channel)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::cancelPendingSend");
+    return XQServiceChannel::cancelPendingSend(channel);
+}
+
+int XQServiceAdaptor::latestError()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::latestError");
+    return XQServiceChannel::latestError();
+}
+
+
+
+int XQServiceAdaptor::setCurrentRequestAsync()
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::setCurrentRequestAsync");
+    XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(d->channelName);
+    return cl->setCurrentRequestAsync();
+}
+
+bool XQServiceAdaptor::completeRequest(int index, const QVariant& retValue)
+{
+    XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::completeRequest");
+    XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(d->channelName);
+    return cl->completeRequest(index, retValue);
+}
+
+
+XQRequestInfo XQServiceAdaptor::requestInfo() const
+{
+    XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(d->channelName);
+    return cl->requestInfo();
+}
+
+#include "xqserviceadaptor.moc"