qthighway/xqservice/src/xqserviceadaptor.cpp
branchRCL_3
changeset 10 cd2778e5acfe
parent 9 5d007b20cfd0
child 11 19a54be74e5e
equal deleted inserted replaced
9:5d007b20cfd0 10:cd2778e5acfe
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 *
       
     5 * This program is free software: you can redistribute it and/or modify
       
     6 * it under the terms of the GNU Lesser General Public License as published by
       
     7 * the Free Software Foundation, version 2.1 of the License.
       
     8 * 
       
     9 * This program is distributed in the hope that it will be useful,
       
    10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12 * GNU Lesser General Public License for more details.
       
    13 *
       
    14 * You should have received a copy of the GNU Lesser General Public License
       
    15 * along with this program.  If not, 
       
    16 * see "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html/".
       
    17 *
       
    18 * Description:                                                         
       
    19 *
       
    20 */                                                                    
       
    21   
       
    22 #include "xqservicelog.h"
       
    23 
       
    24 #include "xqserviceglobal.h"
       
    25 #include "xqserviceadaptor.h"
       
    26 #include "xqservicechannel.h"
       
    27 #include "xqservicethreaddata.h"
       
    28 #include "xqserviceipcclient.h"
       
    29 
       
    30 #include <xqserviceutil.h>
       
    31 #include <xqrequestutil.h>
       
    32 #include <qmetaobject.h>
       
    33 #include <QMap>
       
    34 #include <QDataStream>
       
    35 #include <qatomic.h>
       
    36 #include <QDebug>
       
    37 #include <QVarLengthArray>
       
    38 #include <e32err.h>
       
    39 #include <xqsharablefile.h>
       
    40 
       
    41 /*!
       
    42     \class XQServiceAdaptor
       
    43     \inpublicgroup QtBaseModule
       
    44 
       
    45     \ingroup ipc
       
    46     \brief The XQServiceAdaptor class provides an interface to messages on a XQService IPC channel which simplifies remote signal and slot invocations.
       
    47 
       
    48     Using this class, it is very easy to convert a signal emission into an IPC
       
    49     message on a channel, and to convert an IPC message on a channel into a
       
    50     slot invocation.  In the following example, when the signal \c{valueChanged(int)}
       
    51     is emitted from the object \c source, the IPC message \c{changeValue(int)} will
       
    52     be sent on the channel \c{QPE/Foo}:
       
    53 
       
    54     \code
       
    55     XQServiceAdaptor *adaptor = new XQServiceAdaptor("QPE/Foo");
       
    56     XQServiceAdaptor::connect
       
    57         (source, SIGNAL(valueChanged(int)), adaptor, MESSAGE(changeValue(int)));
       
    58     \endcode
       
    59 
       
    60     Note that we use XQServiceAdaptor::connect() to connect the signal to the
       
    61     IPC message, not QObject::connect().  A common error is to use \c{connect()}
       
    62     without qualifying it with \c{XQServiceAdaptor::} and picking up
       
    63     QObject::connect() by mistake.
       
    64 
       
    65     On the server side of an IPC protocol, the \c{changeValue(int)} message can
       
    66     be connected to the slot \c{setValue()} on \c dest:
       
    67 
       
    68     \code
       
    69     XQServiceAdaptor *adaptor = new XQServiceAdaptor("QPE/Foo");
       
    70     XQServiceAdaptor::connect
       
    71         (adaptor, MESSAGE(changeValue(int)), dest, SLOT(setValue(int)));
       
    72     \endcode
       
    73 
       
    74     Now, whenever the client emits the \c{valueChanged(int)} signal, the
       
    75     \c{setValue(int)} slot will be automatically invoked on the server side,
       
    76     with the \c int parameter passed as its argument.
       
    77 
       
    78     Only certain parameter types can be passed across an IPC boundary in this fashion.
       
    79     The type must be visible to QVariant as a meta-type.  Many simple built-in
       
    80     types are already visible; for user-defined types, use Q_DECLARE_METATYPE()
       
    81     and qRegisterMetaTypeStreamOperators().
       
    82 
       
    83     \sa XQServiceChannel
       
    84 */
       
    85 
       
    86 class XQServiceAdaptorChannel : public XQServiceChannel
       
    87 {
       
    88     Q_OBJECT
       
    89 public:
       
    90     XQServiceAdaptorChannel(const QString& channel, XQServiceAdaptor *adapt)
       
    91         : XQServiceChannel(channel, true, adapt), adaptor(adapt) 
       
    92     {
       
    93         XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::XQServiceAdaptorChannel");
       
    94     }
       
    95     
       
    96     ~XQServiceAdaptorChannel() 
       
    97     {
       
    98         XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::~XQServiceAdaptorChannel");
       
    99     }
       
   100 
       
   101     QVariant receive(const QString& msg, const QByteArray &data, const XQSharableFile &sf);
       
   102     void commandReceive(const XQServiceCommand cmd);
       
   103 
       
   104 private slots:
       
   105     
       
   106 private:
       
   107     XQServiceAdaptor *adaptor;
       
   108 };
       
   109 
       
   110 QVariant XQServiceAdaptorChannel::receive(const QString& msg, const QByteArray &data, const XQSharableFile &sf)
       
   111 {
       
   112     XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::receive");
       
   113     return adaptor->received(msg, data, sf);
       
   114 }
       
   115 
       
   116 void XQServiceAdaptorChannel::commandReceive(const XQServiceCommand cmd)
       
   117 {
       
   118     XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::commandReceive %d", cmd);
       
   119     switch (cmd)
       
   120     {
       
   121         case ReturnValueDelivered:
       
   122             emit adaptor->returnValueDelivered() ;
       
   123             break;
       
   124             
       
   125         case ClientDisconnected:
       
   126             emit adaptor->clientDisconnected() ;
       
   127             break;
       
   128             
       
   129         default:
       
   130             XQSERVICE_DEBUG_PRINT("XQServiceAdaptorChannel::unhandled command %d", cmd);
       
   131         break;
       
   132     }
       
   133 }
       
   134 
       
   135 class XQServiceAdaptorSignalInfo
       
   136 {
       
   137 public:
       
   138     QObject *sender;
       
   139     int signalIndex;
       
   140     int destroyIndex;
       
   141     QString message;
       
   142     int *types;
       
   143     int numArgs;
       
   144 };
       
   145 
       
   146 class XQServiceAdaptorSlotInfo
       
   147 {
       
   148 public:
       
   149     ~XQServiceAdaptorSlotInfo()
       
   150     {
       
   151         XQSERVICE_DEBUG_PRINT("XQServiceAdaptorSlotInfo::~XQServiceAdaptorSlotInfo");
       
   152         qFree(types);
       
   153     }
       
   154 
       
   155     QObject *receiver;
       
   156     int memberIndex;
       
   157     bool destroyed;
       
   158     int returnType;
       
   159     int *types;
       
   160     int numArgs;
       
   161 };
       
   162 
       
   163 class XQServiceAdaptorPrivate : public QObject
       
   164 {
       
   165     // Do not put Q_OBJECT here.
       
   166 public:
       
   167     XQServiceAdaptorPrivate(XQServiceAdaptor *obj, const QString& chan);
       
   168     ~XQServiceAdaptorPrivate();
       
   169 
       
   170     QAtomicInt ref;
       
   171     XQServiceAdaptor *parent;
       
   172     QString channelName;
       
   173     bool connected;
       
   174     const QMetaObject *publishedTo;
       
   175     QMultiMap<QString, XQServiceAdaptorSlotInfo *> invokers;
       
   176     QList<XQServiceAdaptorSignalInfo *> signalList;
       
   177     int slotIndex;
       
   178 
       
   179     static const int QVariantId = -243;
       
   180     static int *connectionTypes(const QByteArray& member, int& nargs);
       
   181     static int typeFromName(const QByteArray& name);
       
   182 
       
   183 protected:
       
   184     int qt_metacall(QMetaObject::Call c, int id, void **a);
       
   185 };
       
   186 
       
   187 XQServiceAdaptorPrivate::XQServiceAdaptorPrivate(XQServiceAdaptor *obj, const QString& chan)
       
   188     : ref(1), channelName(chan)
       
   189 {
       
   190     XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::XQServiceAdaptorPrivate");
       
   191     parent = obj;
       
   192     connected = false;
       
   193     publishedTo = 0;
       
   194 
       
   195     // Fake slots start at this index in the QMetaObject.
       
   196     slotIndex = staticMetaObject.methodCount();
       
   197 }
       
   198 
       
   199 XQServiceAdaptorPrivate::~XQServiceAdaptorPrivate()
       
   200 {
       
   201     XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::~XQServiceAdaptorPrivate");
       
   202     qDeleteAll(invokers);
       
   203 
       
   204     // Disconnect all of the signals associated with this adaptor.
       
   205     int index = slotIndex;
       
   206     XQSERVICE_DEBUG_PRINT("index: %d", index);
       
   207     foreach (XQServiceAdaptorSignalInfo *info, signalList) {
       
   208         XQSERVICE_DEBUG_PRINT("info->signalIndex: %d", info->signalIndex);
       
   209         if (info->signalIndex >= 0) {
       
   210             QMetaObject::disconnect(info->sender, info->signalIndex,
       
   211                                     this, index);
       
   212         }
       
   213         XQSERVICE_DEBUG_PRINT("info->destroyIndex: %d", info->destroyIndex);
       
   214         if (info->destroyIndex >= 0) {
       
   215             QMetaObject::disconnect(info->sender, info->destroyIndex,
       
   216                                     this, index + 1);
       
   217         }
       
   218         qFree(info->types);
       
   219         delete info;
       
   220         index += 2;
       
   221     }
       
   222 }
       
   223 
       
   224 // Get the QVariant type number for a type name.
       
   225 int XQServiceAdaptorPrivate::typeFromName( const QByteArray& type )
       
   226 {
       
   227     XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::typeFromName");
       
   228     XQSERVICE_DEBUG_PRINT("type: %s", type.constData());
       
   229     if (type.endsWith('*')){
       
   230         XQSERVICE_DEBUG_PRINT("Pointer");
       
   231         return QMetaType::VoidStar;
       
   232     }
       
   233     else if ( type.size() == 0 || type == "void" ){
       
   234         XQSERVICE_DEBUG_PRINT("Void");
       
   235         return QMetaType::Void;
       
   236     }
       
   237     else if ( type == "QVariant" ){
       
   238         XQSERVICE_DEBUG_PRINT("QVariant");
       
   239         return XQServiceAdaptorPrivate::QVariantId;
       
   240     }
       
   241     int id = QMetaType::type( type.constData() );
       
   242     XQSERVICE_DEBUG_PRINT("id: %d", id);
       
   243     if ( id != (int)QMetaType::Void )
       
   244         return id;
       
   245     return QVariant::nameToType(type);
       
   246 }
       
   247 
       
   248 // Returns the connection types associated with a signal or slot member.
       
   249 int *XQServiceAdaptorPrivate::connectionTypes( const QByteArray& member, int& nargs )
       
   250 {
       
   251     XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::connectionTypes");
       
   252     XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
       
   253     // Based on Qt's internal queuedConnectionTypes function.
       
   254     nargs = 0;
       
   255     int *types = 0;
       
   256     const char *s = member.constData();
       
   257     while (*s != '\0' && *s != '(') { ++s; }
       
   258     if ( *s == '\0' )
       
   259         return 0;
       
   260     ++s;
       
   261     const char *e = s;
       
   262     while (*e != ')') {
       
   263         ++e;
       
   264         if (*e == ')' || *e == ',')
       
   265             ++nargs;
       
   266     }
       
   267 
       
   268     types = (int *) qMalloc((nargs+1)*sizeof(int));
       
   269     types[nargs] = 0;
       
   270     for (int n = 0; n < nargs; ++n) {
       
   271         e = s;
       
   272         while (*s != ',' && *s != ')')
       
   273             ++s;
       
   274         QByteArray type(e, s-e);
       
   275         ++s;
       
   276 
       
   277         types[n] = typeFromName(type);
       
   278         if (!types[n]) {
       
   279             XQSERVICE_WARNING_PRINT("XQServiceAdaptorPrivate::connectionTypes: Cannot marshal arguments of type '%s'", type.constData());
       
   280             qFree(types);
       
   281             return 0;
       
   282         }
       
   283     }
       
   284     XQSERVICE_DEBUG_PRINT("types: %d", types);
       
   285     return types;
       
   286 }
       
   287 
       
   288 int XQServiceAdaptorPrivate::qt_metacall(QMetaObject::Call c, int id, void **a)
       
   289 {
       
   290     XQSERVICE_DEBUG_PRINT("XQServiceAdaptorPrivate::qt_metacall");
       
   291     id = QObject::qt_metacall(c, id, a);
       
   292     XQSERVICE_DEBUG_PRINT("id: %d", id);
       
   293     if (id < 0)
       
   294         return id;
       
   295     if (c == QMetaObject::InvokeMetaMethod) {
       
   296         XQSERVICE_DEBUG_PRINT("InvokeMetaMethod");
       
   297         // Each signal that we have intercepted has two fake slots
       
   298         // associated with it.  The first is the activation slot.
       
   299         // The second is the destroyed() slot for the signal's object.
       
   300         if (id < signalList.size() * 2) {
       
   301             XQServiceAdaptorSignalInfo *info = signalList[id / 2];
       
   302             if ((id % 2) == 0) {
       
   303                 // The signal we are interested in has been activated.
       
   304                 if (info->types) {
       
   305                     XQSERVICE_DEBUG_PRINT("Signal has been activated");
       
   306                     QList<QVariant> args;
       
   307                     XQSERVICE_DEBUG_PRINT("info->numArgs: %d", info->numArgs);
       
   308                     for (int i = 0; i < info->numArgs; ++i) {
       
   309                         if (info->types[i] != XQServiceAdaptorPrivate::QVariantId) {
       
   310                             QVariant arg(info->types[i], a[i + 1]);
       
   311                             XQSERVICE_DEBUG_PRINT("arg: %s", qPrintable(arg.toString()));
       
   312                             args.append(arg);
       
   313                         } else {
       
   314                             args.append(*((const QVariant *)(a[i + 1])));
       
   315                         }
       
   316                     }
       
   317                     //TODO: CHECK HERE
       
   318                     QVariant retValue;
       
   319                     parent->sendMessage(info->message, args,retValue);
       
   320                 }
       
   321             } else {
       
   322                 XQSERVICE_DEBUG_PRINT("Sender has been destroyed");
       
   323                 // The sender has been destroyed.  Clear the signal indices
       
   324                 // so that we don't try to do a manual disconnect when our
       
   325                 // own destructor is called.
       
   326                 info->signalIndex = -1;
       
   327                 info->destroyIndex = -1;
       
   328             }
       
   329         }
       
   330         id -= signalList.size() * 2;
       
   331     }
       
   332     XQSERVICE_DEBUG_PRINT("id: %d", id);
       
   333     return id;
       
   334 }
       
   335 
       
   336 /*!
       
   337     Construct a Qt Extended IPC message object for \a channel and attach it to \a parent.
       
   338     If \a channel is empty, then messages are taken from the application's
       
   339     \c{appMessage} channel.
       
   340 */
       
   341 XQServiceAdaptor::XQServiceAdaptor(const QString& channel, QObject *parent)
       
   342     : QObject(parent)
       
   343 {
       
   344     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::XQServiceAdaptor");
       
   345     d = new XQServiceAdaptorPrivate(this, channel);
       
   346 }
       
   347 
       
   348 /*!
       
   349 */
       
   350 XQServiceAdaptor::~XQServiceAdaptor()
       
   351 {
       
   352     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::~XQServiceAdaptor");
       
   353     if (!d->ref.deref())
       
   354         delete d;
       
   355     d = 0;
       
   356 }
       
   357 
       
   358 /*!
       
   359     Returns the name of the channel that this adaptor is associated with.
       
   360 */
       
   361 QString XQServiceAdaptor::channel() const
       
   362 {
       
   363     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::channel");
       
   364     XQSERVICE_DEBUG_PRINT("d->channelName: %s", qPrintable(d->channelName));
       
   365     return d->channelName;
       
   366 }
       
   367 
       
   368 /*!
       
   369     Connects \a signal on \a sender to \a member on \a receiver.  Returns true
       
   370     if the receiveion was possible; otherwise returns false.
       
   371 
       
   372     If either \a sender or \a receiver are instances of
       
   373     XQServiceAdaptor, this function will arrange for the signal
       
   374     to be delivered over a Qt Extended IPC channel.  If both \a sender and
       
   375     \a receiver are local, this function is identical
       
   376     to QObject::connect().
       
   377 
       
   378     If the same signal is connected to same slot multiple times,
       
   379     then signal delivery will happen that many times.
       
   380 
       
   381     \sa XQServiceAdaptor::ChannelSelector
       
   382 */
       
   383 bool XQServiceAdaptor::connect(QObject *sender, const QByteArray& signal,
       
   384                           QObject *receiver, const QByteArray& member)
       
   385 {
       
   386     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::connect");
       
   387     XQSERVICE_DEBUG_PRINT("signal: %s", signal.constData());
       
   388     XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
       
   389     XQServiceAdaptor *senderProxy;
       
   390     XQServiceAdaptor *receiverProxy;
       
   391 
       
   392     // Bail out if the parameters are invalid.
       
   393     if (!sender || signal.isEmpty() || !receiver || member.isEmpty()){
       
   394         XQSERVICE_DEBUG_PRINT("Parameters are invalid");
       
   395         return false;
       
   396     }
       
   397 
       
   398     // Resolve the objects to find the remote proxies.
       
   399     senderProxy = qobject_cast<XQServiceAdaptor *>(sender);
       
   400     receiverProxy = qobject_cast<XQServiceAdaptor *>(receiver);
       
   401 
       
   402     // Remove proxies if the signal or member is not tagged with MESSAGE().
       
   403     if (!member.startsWith(QMESSAGE_CODE + '0')){
       
   404         XQSERVICE_DEBUG_PRINT("No received proxy");
       
   405         receiverProxy = 0;
       
   406     }
       
   407     if (!signal.startsWith(QMESSAGE_CODE + '0')){
       
   408         XQSERVICE_DEBUG_PRINT("No sender proxy");
       
   409         senderProxy = 0;
       
   410     }
       
   411 
       
   412     // If neither has a proxy, then use a local connect.
       
   413     if (!senderProxy && !receiverProxy){
       
   414         XQSERVICE_DEBUG_PRINT("Local connect");
       
   415         return QObject::connect(sender, signal, receiver, member);
       
   416     }
       
   417 
       
   418     // If both are still remote proxies, then fail the request.
       
   419     if (senderProxy && receiverProxy) {
       
   420         XQSERVICE_WARNING_PRINT("XQServiceAdaptor::connect: cannot connect MESSAGE() to MESSAGE()");
       
   421         return false;
       
   422     }
       
   423 
       
   424     // Determine which direction the connect needs to happen in.
       
   425     if (receiverProxy) {
       
   426         XQSERVICE_DEBUG_PRINT("Connecting a local signal to a remote slot");
       
   427         // Connecting a local signal to a remote slot.
       
   428         return receiverProxy->connectLocalToRemote(sender, signal, member);
       
   429     } else {
       
   430         XQSERVICE_DEBUG_PRINT("Connecting a remote signal to a local slot");
       
   431         // Connecting a remote signal to a local slot.
       
   432         return senderProxy->connectRemoteToLocal(signal, receiver, member);
       
   433     }
       
   434 }
       
   435 
       
   436 /*!
       
   437     Publishes the signal or slot called \a member on this object on
       
   438     the Qt Extended IPC channel represented by this XQServiceAdaptor.
       
   439 
       
   440     If \a member is a slot, then whenever an application sends a
       
   441     message to the channel with that name, the system will arrange
       
   442     for the slot to be invoked.
       
   443 
       
   444     If \a member is a signal, then whenever this object emits that
       
   445     signal, the system will arrange for a message with that name to
       
   446     be sent on the channel.
       
   447 
       
   448     Returns false if \a member does not refer to a valid signal or slot.
       
   449 
       
   450     \sa publishAll()
       
   451 */
       
   452 bool XQServiceAdaptor::publish(const QByteArray& member)
       
   453 {
       
   454     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::publish");
       
   455     XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
       
   456     // '1' is QSLOT_CODE in Qt 4.4 and below,
       
   457     // '5' is QSLOT_CODE in Qt 4.5 and higher.
       
   458     if (member.size() >= 1 && (member[0] == '1' || member[0] == '5')) {
       
   459         XQSERVICE_DEBUG_PRINT("Exporting a slot");
       
   460         // Exporting a slot.
       
   461         return connectRemoteToLocal("3" + member.mid(1), this, member);
       
   462     } else {
       
   463         XQSERVICE_DEBUG_PRINT("Exporting a sigal");
       
   464         // Exporting a signal.
       
   465         return connectLocalToRemote(this, member, member);
       
   466     }
       
   467 }
       
   468 
       
   469 /*!
       
   470     \enum XQServiceAdaptor::PublishType
       
   471     Type of members to publish via XQServiceAdaptor.
       
   472 
       
   473     \value Signals Publish only signals.
       
   474     \value Slots Publish only public slots.
       
   475     \value SignalsAndSlots Publish both signals and public slots.
       
   476 */
       
   477 
       
   478 /*!
       
   479     Publishes all signals or public slots on this object within subclasses of
       
   480     XQServiceAdaptor.  This is typically called from a subclass constructor.
       
   481     The \a type indicates if all signals, all public slots, or both, should
       
   482     be published.  Private and protected slots will never be published.
       
   483 
       
   484     \sa publish()
       
   485 */
       
   486 void XQServiceAdaptor::publishAll(XQServiceAdaptor::PublishType type)
       
   487 {
       
   488     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::publishAll(1)");
       
   489     publishAll(this,XQServiceAdaptor::staticMetaObject.methodCount(),type);
       
   490 }
       
   491 
       
   492 void XQServiceAdaptor::publishAll(QObject* object,int metCount, XQServiceAdaptor::PublishType type)
       
   493 {
       
   494     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::publishAll(2)");
       
   495     XQSERVICE_DEBUG_PRINT("metCount: %d", metCount);
       
   496     const QMetaObject *meta = object->metaObject();
       
   497     if (meta != d->publishedTo) {
       
   498         int count = meta->methodCount();
       
   499         XQSERVICE_DEBUG_PRINT("count: %d", count);
       
   500         int index;
       
   501         if (d->publishedTo)
       
   502             index = d->publishedTo->methodCount();
       
   503         else
       
   504             index = metCount;
       
   505         XQSERVICE_DEBUG_PRINT("index: %d", index);
       
   506         for (; index < count; ++index) {
       
   507 
       
   508             QMetaMethod method = meta->method(index);
       
   509             if (method.methodType() == QMetaMethod::Slot &&
       
   510                  method.access() == QMetaMethod::Public &&
       
   511                  (type == Slots || type == SignalsAndSlots)) {
       
   512                 QByteArray name = method.signature();
       
   513                 XQSERVICE_DEBUG_PRINT("name: %s", name.constData());
       
   514                 XQSERVICE_DEBUG_PRINT("connectRemoteToLocal");
       
   515                 connectRemoteToLocal("3" + name, object, "1" + name);
       
   516             } else if (method.methodType() == QMetaMethod::Signal &&
       
   517                         (type == Signals || type == SignalsAndSlots)) {
       
   518                 QByteArray name = method.signature();
       
   519                 XQSERVICE_DEBUG_PRINT("name: %s", name.constData());
       
   520                 XQSERVICE_DEBUG_PRINT("connectLocalToRemote");
       
   521                 connectLocalToRemote(object, "2" + name, "3" + name);
       
   522             }
       
   523         }
       
   524         d->publishedTo = meta;
       
   525     }
       
   526 }
       
   527 
       
   528 /*!
       
   529     Sends a message on the Qt Extended IPC channel which will cause the invocation
       
   530     of the single-argument \a member on receiving objects, with the
       
   531     argument \a arg1.
       
   532 */
       
   533 bool XQServiceAdaptor::send(const QByteArray& member, const QVariant &arg1, QVariant &retData)
       
   534 {
       
   535     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(1)");
       
   536     XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
       
   537     XQSERVICE_DEBUG_PRINT("arg1: %s", qPrintable(arg1.toString()));
       
   538     QList<QVariant> args;
       
   539     args.append(arg1);
       
   540     return sendMessage(memberToMessage(member), args, retData);
       
   541 }
       
   542 
       
   543 /*!
       
   544     Sends a message on the Qt Extended IPC channel which will cause the invocation
       
   545     of the double-argument \a member on receiving objects, with the
       
   546     arguments \a arg1 and \a arg2.
       
   547 */
       
   548 bool XQServiceAdaptor::send(const QByteArray& member, const QVariant &arg1, const QVariant &arg2, QVariant &retData)
       
   549 {
       
   550     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(2)");
       
   551     XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
       
   552     XQSERVICE_DEBUG_PRINT("arg1: %s, arg2: %s", qPrintable(arg1.toString()), qPrintable(arg2.toString()));
       
   553     QList<QVariant> args;
       
   554     args.append(arg1);
       
   555     args.append(arg2);
       
   556     return sendMessage(memberToMessage(member), args, retData);
       
   557 }
       
   558 
       
   559 /*!
       
   560     Sends a message on the Qt Extended IPC channel which will cause the invocation
       
   561     of the triple-argument \a member on receiving objects, with the
       
   562     arguments \a arg1, \a arg2, and \a arg3.
       
   563 */
       
   564 bool XQServiceAdaptor::send(const QByteArray& member, const QVariant &arg1,
       
   565                        const QVariant &arg2, const QVariant &arg3, QVariant &retData)
       
   566 {
       
   567     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(3)");
       
   568     XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
       
   569     XQSERVICE_DEBUG_PRINT("arg1: %s, arg2: %s, arg3: %s", qPrintable(arg1.toString()), qPrintable(arg2.toString()), qPrintable(arg3.toString()));
       
   570     QList<QVariant> args;
       
   571     args.append(arg1);
       
   572     args.append(arg2);
       
   573     args.append(arg3);
       
   574     return sendMessage(memberToMessage(member), args, retData);
       
   575 }
       
   576 
       
   577 /*!
       
   578     Sends a message on the Qt Extended IPC channel which will cause the invocation
       
   579     of the multi-argument \a member on receiving objects, with the
       
   580     argument list \a args.
       
   581 */
       
   582 bool XQServiceAdaptor::send(const QByteArray& member, const QList<QVariant>& args, QVariant &retData)
       
   583 {
       
   584     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(4)");
       
   585     XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
       
   586     for(int i=0;i<args.size();++i){
       
   587         XQSERVICE_DEBUG_PRINT("args[%d]: %s", i, qPrintable(args[i].toString()));
       
   588     }
       
   589     return sendMessage(memberToMessage(member), args, retData);
       
   590 }
       
   591 
       
   592 /*!
       
   593     Returns true if the message on the Qt Extended IPC channel corresponding to \a signal
       
   594     has been connected to a local slot; otherwise returns false.
       
   595 */
       
   596 bool XQServiceAdaptor::isConnected(const QByteArray& signal)
       
   597 {
       
   598     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::isConnected");
       
   599     XQSERVICE_DEBUG_PRINT("signal: %s", signal.constData());
       
   600     return d->invokers.contains(memberToMessage(signal));
       
   601 }
       
   602 
       
   603 /*!
       
   604     Converts a signal or slot \a member name into a Qt Extended IPC message name.
       
   605     The default implementation strips the signal or slot prefix number
       
   606     from \a member and then normalizes the name to convert types
       
   607     such as \c{const QString&} into QString.
       
   608 
       
   609     \sa QMetaObject::normalizedSignature()
       
   610 */
       
   611 QString XQServiceAdaptor::memberToMessage(const QByteArray& member)
       
   612 {
       
   613     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::memberToMessage");
       
   614     XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
       
   615     if (member.size() >= 1 && member[0] >= '0' && member[0] <= '9') {
       
   616         return QString::fromLatin1
       
   617             (QMetaObject::normalizedSignature(member.constData() + 1));
       
   618     } else {
       
   619         return QString::fromLatin1(member.data(), member.size());
       
   620     }
       
   621 }
       
   622 
       
   623 QVariant XQServiceAdaptor::received(const QString& msg, const QByteArray& data, const XQSharableFile &sf)
       
   624 {
       
   625     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::received");
       
   626     XQSERVICE_DEBUG_PRINT("\tmsg: %s", qPrintable(msg));
       
   627     XQSERVICE_DEBUG_PRINT("\tdata: %s", data.constData());
       
   628     QVariant returnValue;
       
   629     bool found = false;
       
   630     // Increase the reference count on the private data just
       
   631     // in case the XQServiceAdaptor is deleted by one of the slots.
       
   632     XQServiceAdaptorPrivate *priv = d;
       
   633     priv->ref.ref();
       
   634 
       
   635     // Iterate through the slots for the message and invoke them.
       
   636     QMultiMap<QString, XQServiceAdaptorSlotInfo *>::ConstIterator iter;
       
   637     for (iter = priv->invokers.find(msg);
       
   638          iter != priv->invokers.end() && iter.key() == msg; ++iter) {
       
   639         XQServiceAdaptorSlotInfo *info = iter.value();
       
   640         if (info->destroyed){
       
   641             XQSERVICE_DEBUG_PRINT("\tDestroyed");
       
   642             continue;
       
   643         }
       
   644 
       
   645         // Convert "data" into a set of arguments suitable for qt_metacall.
       
   646         QDataStream stream(data);
       
   647         QList<QVariant> args;
       
   648         // a[0] is return value (numArgs+1)
       
   649         QVarLengthArray<void *, 32> a(info->numArgs + 1);
       
   650         
       
   651         XQSERVICE_DEBUG_PRINT("\tinfo->returnType: %d", info->returnType);
       
   652         
       
   653         if (info->returnType != (int)QVariant::Invalid) {
       
   654             returnValue = QVariant(info->returnType, (const void *)0);
       
   655             a[0] = returnValue.data();
       
   656         } else {
       
   657             a[0] = 0;
       
   658         }
       
   659         // Need to pick also the last XQRequestInfo form the stream
       
   660         // That's why iterating up to numArgs+1
       
   661         
       
   662         int reqInfoIndex = info->numArgs;
       
   663 
       
   664         
       
   665         for (int arg = 0; arg < info->numArgs+1; ++arg)             
       
   666             {
       
   667             XQSERVICE_DEBUG_PRINT("\tDesserialize argument: %d", arg);
       
   668             if (arg == reqInfoIndex)
       
   669             {
       
   670                 // The last argument should be the request index
       
   671                 XQSERVICE_DEBUG_PRINT("\tDesserialize XQRequestInfo");
       
   672                 QVariant v;
       
   673                 stream >> v;
       
   674                 XQSERVICE_DEBUG_PRINT("\tXQRequestInfo:QVariant type=%s", v.typeName());
       
   675                 if (QString(v.typeName()) == QString("XQRequestInfo"))
       
   676                 {
       
   677                     XQRequestInfo info = v.value<XQRequestInfo>();
       
   678                     
       
   679                     //bring foreground or background based on RequestInfo from client side.
       
   680                     bool bg = info.isBackground();
       
   681                     bool fg = info.isForeground();
       
   682                     if (bg && !fg)
       
   683                     {
       
   684                         XQSERVICE_DEBUG_PRINT("\tApply background option");
       
   685                         XQServiceUtil::toBackground(true);
       
   686                     }
       
   687                     else if (fg && !bg)
       
   688                     {
       
   689                         XQSERVICE_DEBUG_PRINT("\tApply foreground option");
       
   690                         XQServiceUtil::toBackground(false);
       
   691                     }
       
   692                     // If both off or both on, do not do anything
       
   693                     
       
   694                     XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(d->channelName);
       
   695                     // Attach to current request before the metacall below !
       
   696                     cl->setRequestInfo(info);
       
   697                 }
       
   698             }
       
   699             else if (info->types[arg] == XQServiceAdaptorPrivate::QVariantId)
       
   700             {
       
   701                 // We need to handle QVariant specially because we actually
       
   702                 // need the type header in this case.
       
   703                 QVariant temp;
       
   704                 stream >> temp;
       
   705 
       
   706                 XQSERVICE_DEBUG_PRINT("\tQVariantId:QVariant type=%s", temp.typeName());
       
   707 
       
   708                 if (QString(temp.typeName()) == QString("XQSharableFile"))
       
   709                 {
       
   710                     //apply the patch
       
   711                     if ( sf.isValid())
       
   712                     {
       
   713                         temp = qVariantFromValue( sf );
       
   714                     }
       
   715                 }
       
   716 
       
   717                 args.append(temp);
       
   718                 a[arg + 1] = (void *)&(args[arg]);
       
   719             }
       
   720             else {
       
   721                 //
       
   722                 // The default handling
       
   723                 //
       
   724                 QVariant temp;
       
   725                 stream >> temp;
       
   726                 
       
   727                 XQSERVICE_DEBUG_PRINT("\tDefault:QVariant type=%s", temp.typeName());
       
   728                 
       
   729                 if (QString(temp.typeName()) == QString("XQSharableFile"))
       
   730                     {
       
   731                     //apply the patch
       
   732                     if ( sf.isValid())
       
   733                         {
       
   734                         temp = qVariantFromValue( sf );
       
   735                         }
       
   736                     }
       
   737                 
       
   738                 args.append(temp);
       
   739                 a[arg + 1] = (void *)(args[arg].data());
       
   740             }
       
   741         }
       
   742 
       
   743         // Invoke the specified slot.
       
   744     #if !defined(QT_NO_EXCEPTIONS)
       
   745         try {
       
   746     #endif
       
   747             XQSERVICE_DEBUG_PRINT("Try to make metacall");
       
   748             info->receiver->qt_metacall
       
   749                 (QMetaObject::InvokeMetaMethod, info->memberIndex, a.data());
       
   750             found = true;
       
   751     #if !defined(QT_NO_EXCEPTIONS)
       
   752         } catch (...) {
       
   753         }
       
   754     #endif
       
   755     }
       
   756     if (!found)
       
   757         {
       
   758         XQSERVICE_DEBUG_PRINT("Not found");
       
   759         XQService::serviceThreadData()->setLatestError(XQService::EMessageNotFound);
       
   760         }
       
   761     // Decrease the reference count and delete if necessary.
       
   762     if (!priv->ref.deref())
       
   763         delete priv;
       
   764     
       
   765     XQSERVICE_DEBUG_PRINT("returnValue: %s", qPrintable(returnValue.toString()));
       
   766     return returnValue;
       
   767 }
       
   768 
       
   769 void XQServiceAdaptor::receiverDestroyed()
       
   770 {
       
   771     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::receiverDestroyed");
       
   772     // Mark all slot information blocks that match the receiver
       
   773     // as destroyed so that we don't try to invoke them again.
       
   774     QObject *obj = sender();
       
   775     QMultiMap<QString, XQServiceAdaptorSlotInfo *>::Iterator it;
       
   776     for (it = d->invokers.begin(); it != d->invokers.end(); ++it) {
       
   777         if (it.value()->receiver == obj)
       
   778             it.value()->destroyed = true;
       
   779     }
       
   780 }
       
   781 
       
   782 bool XQServiceAdaptor::connectLocalToRemote
       
   783     (QObject *sender, const QByteArray& signal, const QByteArray& member)
       
   784 {
       
   785     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::connectLocalToRemote");
       
   786     XQSERVICE_DEBUG_PRINT("sender->objectName(): %s", qPrintable(sender->objectName()));
       
   787     XQSERVICE_DEBUG_PRINT("signal: %s", signal.constData());
       
   788     XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
       
   789     XQServiceAdaptorSignalInfo *info = new XQServiceAdaptorSignalInfo();
       
   790     info->sender = sender;
       
   791     info->message = memberToMessage(member);
       
   792 
       
   793     // Resolve the signal name on the sender object.
       
   794     if (signal.size() > 0) {
       
   795         if (signal[0] != (QSIGNAL_CODE + '0')) {
       
   796             XQSERVICE_WARNING_PRINT("XQServiceAdaptor: `%s' is not a valid signal specification", signal.constData());
       
   797             delete info;
       
   798             return false;
       
   799         }
       
   800         QByteArray signalName =
       
   801             QMetaObject::normalizedSignature(signal.constData() + 1);
       
   802         info->signalIndex
       
   803             = sender->metaObject()->indexOfSignal(signalName.constData());
       
   804         XQSERVICE_DEBUG_PRINT("info->signalIndex: %d", info->signalIndex);
       
   805         if (info->signalIndex < 0) {
       
   806             XQSERVICE_WARNING_PRINT("XQServiceAdaptor: no such signal: %s::%s",
       
   807                                     sender->metaObject()->className(), signalName.constData());
       
   808             delete info;
       
   809             return false;
       
   810         }
       
   811         info->destroyIndex
       
   812             = sender->metaObject()->indexOfSignal("destroyed()");
       
   813         info->types = XQServiceAdaptorPrivate::connectionTypes
       
   814             (signalName, info->numArgs);
       
   815     } else {
       
   816         XQSERVICE_DEBUG_PRINT("No signal");
       
   817         delete info;
       
   818         return false;
       
   819     }
       
   820 
       
   821     // Connect up the signals.
       
   822     int index = d->slotIndex + d->signalList.size() * 2;
       
   823     XQSERVICE_DEBUG_PRINT("index: %d", index);
       
   824     QMetaObject::connect(sender, info->signalIndex, d, index,
       
   825                          Qt::DirectConnection, 0);
       
   826     if (info->destroyIndex >= 0) {
       
   827         QMetaObject::connect(sender, info->destroyIndex, d, index + 1,
       
   828                              Qt::DirectConnection, 0);
       
   829     }
       
   830 
       
   831     // Add the signal information to the active list.
       
   832     d->signalList.append(info);
       
   833     return true;
       
   834 }
       
   835 
       
   836 bool XQServiceAdaptor::connectRemoteToLocal
       
   837     (const QByteArray& signal, QObject *receiver, const QByteArray& member)
       
   838 {
       
   839     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::connectRemoteToLocal");
       
   840     XQSERVICE_DEBUG_PRINT("signal: %s", signal.constData());
       
   841     XQSERVICE_DEBUG_PRINT("receiver->objectName(): %s", qPrintable(receiver->objectName()));
       
   842     XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
       
   843     // Make sure that we are actively monitoring the channel for messages.
       
   844     if (!d->connected) {
       
   845         XQSERVICE_DEBUG_PRINT("Try to connect to channel");
       
   846         QString chan = d->channelName;
       
   847         // Short-cut the signal emits in XQServiceChannel for greater
       
   848         // performance when dispatching incoming messages.
       
   849         XQServiceAdaptorChannel* adaptorChannel = new XQServiceAdaptorChannel(chan, this);
       
   850         bool ret = adaptorChannel ? adaptorChannel->connectChannel() : false;
       
   851         XQSERVICE_DEBUG_PRINT("ret: %d", ret);
       
   852         if (!ret) {
       
   853             return ret;
       
   854         }
       
   855         d->connected = true;
       
   856     }
       
   857 
       
   858     // Create a slot invoker to handle executing the member when necessary.
       
   859     XQServiceAdaptorSlotInfo *info = new XQServiceAdaptorSlotInfo();
       
   860     QByteArray name;
       
   861     if (member.size() > 0 && member[0] >= '0' && member[0] <= '9') {
       
   862         // Strip off the member type code.
       
   863         name = QMetaObject::normalizedSignature(member.constData() + 1);
       
   864     } else {
       
   865         name = QMetaObject::normalizedSignature(member.constData());
       
   866     }
       
   867     info->receiver = receiver;
       
   868     info->returnType = 0;
       
   869     info->types = 0;
       
   870     info->numArgs = 0;
       
   871     info->destroyed = false;
       
   872     if (receiver && name.size() > 0) {
       
   873         info->memberIndex
       
   874             = receiver->metaObject()->indexOfMethod(name.constData());
       
   875         XQSERVICE_DEBUG_PRINT("info->memberIndex: %d", info->memberIndex);
       
   876         if (info->memberIndex != -1) {
       
   877             connect(receiver, SIGNAL(destroyed()), this, SLOT(receiverDestroyed()));
       
   878             QMetaMethod method = receiver->metaObject()->method(info->memberIndex);
       
   879             info->returnType = XQServiceAdaptorPrivate::typeFromName(method.typeName());
       
   880             info->types = XQServiceAdaptorPrivate::connectionTypes(name, info->numArgs);
       
   881             if (!(info->types))
       
   882                 info->destroyed = true;
       
   883         } else {
       
   884             XQSERVICE_WARNING_PRINT("XQServiceAdaptor: no such member: %s::%s",
       
   885                                      receiver->metaObject()->className(), name.constData());
       
   886         }
       
   887     } else {
       
   888         info->memberIndex = -1;
       
   889     }
       
   890     if (info->memberIndex == -1) {
       
   891         XQSERVICE_DEBUG_PRINT("No receiver");
       
   892         delete info;
       
   893         return false;
       
   894     }
       
   895     d->invokers.insert(memberToMessage(signal), info);
       
   896     return true;
       
   897 }
       
   898 
       
   899 bool XQServiceAdaptor::sendMessage(const QString& msg, const QList<QVariant>& args, QVariant &retData)
       
   900 {
       
   901     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::sendMessage");
       
   902     return send(d->channelName, msg, args, retData);
       
   903 }
       
   904 
       
   905 
       
   906 bool XQServiceAdaptor::send(const QString& channel,
       
   907                             const QString& msg, 
       
   908                             const QList<QVariant>& args,
       
   909                             QVariant& retValue,
       
   910                             bool sync,
       
   911                             XQServiceRequestCompletedAsync* rc)
       
   912 {
       
   913     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(1). No user data");
       
   914     return send(channel,msg,args,retValue,sync,rc,NULL);
       
   915 }
       
   916 
       
   917 bool XQServiceAdaptor::send(const QString& channel,
       
   918                             const QString& msg, 
       
   919                             const QList<QVariant>& args,
       
   920                             QVariant& retValue,
       
   921                             bool sync,
       
   922                             XQServiceRequestCompletedAsync* rc,
       
   923                             const void *userData)
       
   924 {
       
   925     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::send(2)");
       
   926     XQSERVICE_DEBUG_PRINT("channel: %s, sync: %d", qPrintable(channel), sync);
       
   927     XQSERVICE_DEBUG_PRINT("msg: %s", qPrintable(msg));
       
   928     XQSERVICE_DEBUG_PRINT("userdata: %x",(int)userData);
       
   929     for(int i=0;i<args.size();++i){
       
   930         XQSERVICE_DEBUG_PRINT("args[%d]:type=%s,value=%s", i, args[i].typeName(), qPrintable(args[i].toString()));
       
   931     }
       
   932     if (!sync && !rc) {
       
   933         // Something wrong as no callback given
       
   934         XQService::serviceThreadData()->setLatestError(XQService::EArgumentError);
       
   935         return false;
       
   936     }
       
   937     QByteArray array;
       
   938     QDataStream stream(&array, QIODevice::WriteOnly | QIODevice::Append);
       
   939     QList<QVariant>::ConstIterator iter;
       
   940     for (iter = args.begin(); iter != args.end(); ++iter) {
       
   941         stream << *iter;
       
   942     }
       
   943     // Stream is flushed and closed at this point.
       
   944     return XQServiceChannel::send(channel, msg, array, retValue, sync, rc, userData);
       
   945 }
       
   946 
       
   947 bool XQServiceAdaptor::cancelPendingSend(const QString& channel)
       
   948 {
       
   949     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::cancelPendingSend");
       
   950     return XQServiceChannel::cancelPendingSend(channel);
       
   951 }
       
   952 
       
   953 int XQServiceAdaptor::latestError()
       
   954 {
       
   955     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::latestError");
       
   956     return XQServiceChannel::latestError();
       
   957 }
       
   958 
       
   959 
       
   960 
       
   961 int XQServiceAdaptor::setCurrentRequestAsync()
       
   962 {
       
   963     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::setCurrentRequestAsync");
       
   964     XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(d->channelName);
       
   965     return cl->setCurrentRequestAsync();
       
   966 }
       
   967 
       
   968 bool XQServiceAdaptor::completeRequest(int index, const QVariant& retValue)
       
   969 {
       
   970     XQSERVICE_DEBUG_PRINT("XQServiceAdaptor::completeRequest");
       
   971     XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(d->channelName);
       
   972     return cl->completeRequest(index, retValue);
       
   973 }
       
   974 
       
   975 
       
   976 XQRequestInfo XQServiceAdaptor::requestInfo() const
       
   977 {
       
   978     XQServiceIpcClient *cl = XQService::serviceThreadData()->clientConnection(d->channelName);
       
   979     return cl->requestInfo();
       
   980 }
       
   981 
       
   982 #include "xqserviceadaptor.moc"