qthighway/xqservice/src/xqserviceprovider.cpp
changeset 24 9d760f716ca8
parent 1 2b40d63a9c3d
child 26 3d09643def13
equal deleted inserted replaced
19:46686fb6258c 24:9d760f716ca8
    28 #include <xqserviceadaptor.h>
    28 #include <xqserviceadaptor.h>
    29 //#include <xqserviceservice.h>
    29 //#include <xqserviceservice.h>
    30 #include <xqserviceutil.h>
    30 #include <xqserviceutil.h>
    31 
    31 
    32 /*!
    32 /*!
       
    33     \class ServiceAdaptorProxy
       
    34     \brief Proxy class for converting signal and slot members into IPC message names
       
    35 */
       
    36 class ServiceAdaptorProxy : public XQServiceAdaptor
       
    37 {
       
    38     Q_OBJECT
       
    39 
       
    40 public:
       
    41     ServiceAdaptorProxy(const QString &channel, QObject *parent=0);
       
    42     virtual ~ServiceAdaptorProxy() ;
       
    43     
       
    44     QString memberToMessage( const QByteArray& member );
       
    45 };
       
    46 
       
    47 ServiceAdaptorProxy::ServiceAdaptorProxy(const QString &channel, QObject *parent) :
       
    48         XQServiceAdaptor(channel, parent) 
       
    49 {
       
    50     XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::ServiceAdaptorProxy");
       
    51     XQSERVICE_DEBUG_PRINT("channel: %s", qPrintable(channel));
       
    52 }
       
    53 
       
    54 ServiceAdaptorProxy::~ServiceAdaptorProxy()
       
    55 {
       
    56     XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::~ServiceAdaptorProxy");
       
    57 }
       
    58 
       
    59 QString ServiceAdaptorProxy::memberToMessage( const QByteArray& member )
       
    60 {
       
    61     XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::memberToMessage");
       
    62     XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
       
    63 // TO BE CHECKED
       
    64 //    return m_channel + "::" + XQServiceAdaptor::memberToMessage( member );
       
    65     return XQServiceAdaptor::memberToMessage( member );
       
    66 }
       
    67 
       
    68 /*!
       
    69     \class XQServiceProvider_Private
       
    70     \inpublicgroup QtBaseModule
       
    71 
       
    72     \brief Private implementation of XQServiceProvider
       
    73 */
       
    74 class XQServiceProvider_Private
       
    75 {
       
    76 public:
       
    77     XQServiceProvider_Private(const QString &service);
       
    78 
       
    79     ~XQServiceProvider_Private();
       
    80     
       
    81     XQServiceAdaptor *m_adaptor;
       
    82 
       
    83     QString m_service;
       
    84     bool m_publishAllCalled;
       
    85     QObject* plugin;
       
    86 };
       
    87 
       
    88 XQServiceProvider_Private::XQServiceProvider_Private(const QString &service) :
       
    89         m_adaptor(NULL),
       
    90         m_service(service),
       
    91         m_publishAllCalled(false),
       
    92 		plugin(NULL)
       
    93 {
       
    94     XQSERVICE_DEBUG_PRINT("XQServiceProvider_Private::XQServiceProvider_Private");
       
    95     XQSERVICE_DEBUG_PRINT("service: %s", qPrintable(service));
       
    96     m_adaptor = new ServiceAdaptorProxy(service);
       
    97 }
       
    98 
       
    99 XQServiceProvider_Private::~XQServiceProvider_Private()
       
   100 {
       
   101     XQSERVICE_DEBUG_PRINT("XQServiceProvider_Private::~XQServiceProvider_Private");
       
   102     delete m_adaptor;
       
   103 }
       
   104 
       
   105 /*!
    33     \class XQServiceProvider
   106     \class XQServiceProvider
    34     \inpublicgroup QtBaseModule
   107     \inpublicgroup QtBaseModule
    35 
   108 
    36     \brief The XQServiceProvider class provides an interface to messages on a XQService service
   109     \brief The XQServiceProvider class provides an interface to messages on a XQService service
    37     which simplifies remote slot invocations
   110     which simplifies remote slot invocations
    38 
   111 
    39     Service messages consist of a service name, a message name, and a list of parameter values.
   112     Service messages consist of a service name, a message name, and a list of parameter values.
    40     Qt extension extension dispatches service messages to the applications associated with the service
   113     Qt extension dispatches service messages to the applications associated with the service
    41     name, on the application's \c{QPE/Application/appname} channel, where
   114     name, on the application's \c{QPE/Application/appname} channel, where
    42     \c{appname} is the application's name.
   115     \c{appname} is the application's name.
    43 
   116 
       
   117     <b>Service registration</b> \n
       
   118     Service provider need to register it's service into the system before they can be used by
       
   119     the service client. Registration is done by creating a XML formatted service configuration
       
   120     file and defining the service in the provider's .pro-file. QMake will notice service provider
       
   121     from the .pro-file, with help of the service.prf file, and generate a make file that uses
       
   122     a helper application xqsreg.exe. The helper application sqsreg.exe will generate an application
       
   123     registration resource file ( _reg.rss) from the configuration-file and provider's definitions
       
   124     that include the needed declarations for the services provided.
       
   125     
       
   126     <b>Service Names Allocation</b> \n
       
   127     The harmonize service and interface names the Symba specific names and guidelines can be found
       
   128     from http://s60wiki.nokia.com/S60Wiki/QtFw_for_S60_coding_conventions/Service_name_registry#Service.
       
   129 
       
   130     Before implementing a service you need to allocate the name according to the guidelines. Please
       
   131     inform intended service clients (customers) and matti.parnanen@nokia.com.
       
   132     
       
   133     <b>Service Configuration File</b> \n
       
   134     All the service configuration are added to the run-time service registry to make them available
       
   135     for service discovery and creating service requests.
       
   136     \note Only one service element with multiple interface is supported!
       
   137     
       
   138     To support services a new configuration was introduced to qmake and two new variables for
       
   139     that configuration:
       
   140     
       
   141     \code
       
   142         CONFIG = service
       
   143         service.file = <service configuration file path>
       
   144         service.options = <embeddable> (optional, default not embeddable), <hidden> (optional, default not hidden) 
       
   145     \endcode
       
   146     
       
   147     The fornat of the service configuration file is same as XML format used in Qt Service Framework.
       
   148     Example configuration file:
       
   149     
       
   150     \code
       
   151         <?xml version="1.0" encoding="utf-8" ?>
       
   152         <service>
       
   153             <name>Music Fetcher</name>
       
   154             <filepath>No path</filepath>
       
   155             <description>Music Fetcher</description>
       
   156             <interface>
       
   157                 <name><b>com.nokia.symbian.IMusicFetch</b></name>
       
   158                 <version>1.0</version>
       
   159                 <description>Interface for fetching music files</description>
       
   160             </interface>
       
   161         </service>
       
   162     \endcode
       
   163     
       
   164     \code
       
   165         <ELEMENT service ( name, filepath, description?, interface+ ) >
       
   166         <ELEMENT description ( #CDATA ) >
       
   167         <ELEMENT filepath ( #PCDATA ) >
       
   168         <ELEMENT interface ( '''name''', version, description?, capabilities?, customproperty* ) >
       
   169         <ELEMENT capabilities ( #PCDATA ) >
       
   170         <ELEMENT name ( #PCDATA ) >
       
   171         <ELEMENT version ( #PCDATA ) >
       
   172         <ELEMENT customproperty ( #CDATA ) >
       
   173         <ATTLIST customproperty key NMTOKEN #REQUIRED >
       
   174     \endcode
       
   175     
       
   176     Also the old format described below is supported, With old format you can not have custom properties, which
       
   177     for example are used for AIW purposes.
       
   178     \code
       
   179         <ELEMENT service ( description?, interface+ ) >
       
   180         <ATTLIST service name #CDATA  #REQUIRED >
       
   181         <ATTLIST service filepath #CDATA  #REQUIRED >
       
   182         <ELEMENT description ( #CDATA ) >
       
   183         <ELEMENT interface ( description? ) >
       
   184         <ATTLIST interface '''name''' #CDATA  #REQUIRED >
       
   185         <ATTLIST interface version #CDATA  #REQUIRED >
       
   186         <ATTLIST interface capabilities #CDATA  #REQUIRED >
       
   187     \endcode
       
   188     
       
   189     <b>Changing service or interface names</b> \n
       
   190     Before you think about changing the name of the already released and used service implementation, read this
       
   191     http://s60wiki.nokia.com/S60Wiki/QtFw_for_S60_coding_conventions/Service_name_registry#About_changing_service_or_interface_names
       
   192     first.
       
   193     
       
   194     The basic message is the service name, interface name and operation (message) slot signatures for the API. And for API changes you have to apply development time API deprecation process.
       
   195     
       
   196     <b>Service Registration tools</b> \n
       
   197     The needed utility files for service registration:
       
   198     - xqsreg.exe should be in \epoc32\tools or some other directory that can be found from the path
       
   199     - service.prf should be in \epoc32\tools\qt\mkspecs\features\symbian directory.
       
   200     
       
   201     If necessary you can copy those files to target directories from qthighway/bin.
       
   202     
       
   203     Sources for the xqsreg.exe can be found from the qthighway\xqsreg and it is also possible to compile it.
       
   204         - cd \qthighway\xqsreg
       
   205         - qmake -platform win32-mwc
       
   206         - make
       
   207     
       
   208     Usage: \n
       
   209     How to create a simple synchronously working service provider?
       
   210     \code
       
   211         class YourService : public XQServiceProvider
       
   212             {
       
   213             Q_OBJECT
       
   214 
       
   215             public:
       
   216                 YourService ( ServiceApp *parent = 0 );
       
   217                 ~YourService ();
       
   218 
       
   219             public slots:
       
   220                 void functionName1(); 
       
   221                 int functionName2(const QString& number, int times);
       
   222 
       
   223             private:
       
   224                 ServiceApp *mServiceApp;
       
   225             };
       
   226     \endcode
       
   227     
       
   228     Implementation:
       
   229     \code
       
   230         YourService::YourService(ServiceApp* parent) 
       
   231         : XQServiceProvider(QLatin1String("yourservice.Interface"), parent), mServiceApp(parent)
       
   232             {
       
   233             publishAll();
       
   234             }
       
   235 
       
   236         YourService::~YourService() { } 
       
   237 
       
   238         void YourService::functionName1() { } 
       
   239 
       
   240         int YourService::functionName2(const QString& number, int times)
       
   241             {
       
   242             int returnValue = 1;
       
   243             return returnValue;
       
   244             }
       
   245     \endcode
       
   246     
       
   247     Additions to .pro-file:
       
   248     \code
       
   249         CONFIG += service
       
   250         SERVICE.FILE = service_conf.xml
       
   251         SERVICE.OPTIONS = embeddable
       
   252         SERVICE.OPTIONS += hidden
       
   253     \endcode
       
   254     
       
   255     Service configuration file (service_conf.xml):
       
   256     \code
       
   257     <?xml version="1.0" encoding="utf-8" ?>
       
   258     <service>
       
   259         <name>yourservice</name>
       
   260         <filepath>No path</filepath>
       
   261         <description>Service description</description>
       
   262         <interface>
       
   263             <name>Interface</name>
       
   264             <version>1.0</version>
       
   265             <description>Interface description</description>
       
   266         </interface>
       
   267     </service>
       
   268     \endcode
       
   269     
       
   270     How to create a simple asynchronously working service provider?
       
   271     Header:
       
   272     \code
       
   273         class YourService : public XQServiceProvider
       
   274         {
       
   275 
       
   276         Q_OBJECT
       
   277 
       
   278         public:
       
   279             YourService ( ServiceApp *parent = 0 );
       
   280             ~YourService ();
       
   281             void compleAsyncFunction();
       
   282 
       
   283         public slots:
       
   284             void functionName1(); 
       
   285             int functionName2(const QString& number, int times);
       
   286 
       
   287         private:
       
   288             ServiceApp *mServiceApp;
       
   289             int mAsyncRequestIndex;
       
   290             QVariant mReturnValue;
       
   291          
       
   292         };
       
   293     \endcode
       
   294     
       
   295     Implementation:
       
   296     \code
       
   297         YourService::YourService(ServiceApp* parent) 
       
   298         : XQServiceProvider(QLatin1String("yourservice.Interface"), parent), mServiceApp(parent)
       
   299             {
       
   300             publishAll();
       
   301             }
       
   302 
       
   303         YourService::~YourService() { } 
       
   304 
       
   305         void YourService::compleAsyncFunction()
       
   306             {
       
   307             completeRequest(mAsyncRequestIndex, mReturnValue);
       
   308             }
       
   309 
       
   310         void YourService::functionName1() 
       
   311             { 
       
   312             mAsyncRequestIndex = setCurrentRequestAsync();
       
   313             mReturnValue.setValue(0);
       
   314             } 
       
   315 
       
   316         int YourService::functionName2(const QString& number, int times)
       
   317             {
       
   318             mAsyncRequestIndex = setCurrentRequestAsync();
       
   319             mReturnValue.setValue(1);
       
   320             return mReturnValue.toInt();
       
   321             }
       
   322     \endcode
       
   323     
       
   324     <b>Examples:</b> \n
    44     The use of XQServiceProvider will be demonstrated using the \c{Time}
   325     The use of XQServiceProvider will be demonstrated using the \c{Time}
    45     service.  This has a single message called \c{editTime()} which asks
   326     service.  This has a single message called \c{editTime()} which asks
    46     the service to pop up a dialog allowing the user to edit the current time.
   327     the service to pop up a dialog allowing the user to edit the current time.
    47 
       
    48     \code
   328     \code
    49     class TimeService : public XQServiceProvider
   329     class TimeService : public XQServiceProvider
    50     {
   330     {
    51         Q_OBJECT
   331         Q_OBJECT
    52     public:
   332     public:
    72     \code
   352     \code
    73     XQServiceRequest req( "Time", "editTime()" );
   353     XQServiceRequest req( "Time", "editTime()" );
    74     req << QTime::currentTime();
   354     req << QTime::currentTime();
    75     req.send();
   355     req.send();
    76     \endcode
   356     \endcode
    77 
   357     
    78 */
   358     <b>URI viewer</b> \n
    79 
   359     This is a simple example for implementing out-of-process scheme handlers.
    80 class ServiceAdaptorProxy : public XQServiceAdaptor
   360     - "http", "https" and are handled via standard QDesktopServices::openUrl() function. 
    81 {
   361        This is fire-and-forget launch. The options are ignored and no control and signals available after the launch.
    82     Q_OBJECT
   362     - "appto" is routed to Activity Manager for opening the attached activity.
    83 
   363       This is fire-and-forget launch. The options are ignored and no control and signals available after the launch.
    84 public:
   364     - The "file" scheme is handled as the QFile based create below. 
    85     ServiceAdaptorProxy(const QString &channel, QObject *parent=0);
   365       So the com.nokia.symbian.IFileView interface is applied as for the QFile.
    86     virtual ~ServiceAdaptorProxy() ;
   366     
    87     
   367     Service application needs to publish support for:
    88     QString memberToMessage( const QByteArray& member );
   368     - The common interface "com.nokia.symbian.IUriView", and
    89 };
   369     - The scheme(s), like "testo" in the example below. The custom custom property "schemes" contains one or more schemes as comma separated list (CSV)
    90 
   370     - The slot "view(QString)" to view the URI
    91 ServiceAdaptorProxy::ServiceAdaptorProxy(const QString &channel, QObject *parent) :
   371 
    92         XQServiceAdaptor(channel, parent) 
   372     \code
    93 {
   373         <?xml version="1.0" encoding="utf-8" ?>
    94     XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::ServiceAdaptorProxy");
   374         <service>
    95     XQSERVICE_DEBUG_PRINT("channel: %s", qPrintable(channel));
   375           <name>serviceapp</name>
    96 }
   376           <filepath>No path</filepath>
    97 
   377           <description>Test service</description>
    98 ServiceAdaptorProxy::~ServiceAdaptorProxy()
   378           <interface>
    99 {
   379              <name>com.nokia.symbian.IUriView</name>
   100     XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::~ServiceAdaptorProxy");
   380              <version>1.0</version>
   101 }
   381              <description>Interface for showing URIs</description>
   102 
   382              <customproperty key="schemes">testto</customproperty>
   103 QString ServiceAdaptorProxy::memberToMessage( const QByteArray& member )
   383            </interface>
   104 {
   384         </service>
   105     XQSERVICE_DEBUG_PRINT("ServiceAdaptorProxy::memberToMessage");
   385     \endcode
   106     XQSERVICE_DEBUG_PRINT("member: %s", member.constData());
   386     
   107 // TO BE CHECKED
   387     An service application that offers support for a scheme implements the common "UriService" with the pre-defined "view" slot:
   108 //    return m_channel + "::" + XQServiceAdaptor::memberToMessage( member );
   388     
   109     return XQServiceAdaptor::memberToMessage( member );
   389     \code
   110 }
   390         class UriService : public XQServiceProvider
   111 
   391         {
   112 class XQServiceProvider_Private
   392             Q_OBJECT
   113 {
   393             public:
   114 public:
   394                 UriService( ServiceApp *parent = 0 );
   115     XQServiceProvider_Private(const QString &service);
   395                 ~UriService();
   116 
   396                 bool asyncAnswer() {return mAsyncAnswer;}
   117     ~XQServiceProvider_Private();
   397                 void complete(bool ok);
   118     
   398                 
   119     XQServiceAdaptor *m_adaptor;
   399             public slots:
   120 
   400                 bool view(const QString& uri);
   121     QString m_service;
   401                 
   122     bool m_publishAllCalled;
   402             private slots:
   123     QObject* plugin;
   403                 void handleClientDisconnect();
   124 };
   404 
   125 
   405             private:
   126 XQServiceProvider_Private::XQServiceProvider_Private(const QString &service) :
   406                 ServiceApp* mServiceApp;
   127         m_adaptor(NULL),
   407                 bool mAsyncAnswer;
   128         m_service(service),
   408                 int mAsyncReqId;
   129         m_publishAllCalled(false),
   409                 bool mRetValue;
   130 		plugin(NULL)
   410         };
   131 {
   411     \endcode
   132     XQSERVICE_DEBUG_PRINT("XQServiceProvider_Private::XQServiceProvider_Private");
   412     
   133     XQSERVICE_DEBUG_PRINT("service: %s", qPrintable(service));
   413     Client application accesses the service via the URI:
   134     m_adaptor = new ServiceAdaptorProxy(service);
   414     
   135 }
   415     \code
   136 
   416         // Assume in example we have own scheme "testo" but this can be applied to 
   137 XQServiceProvider_Private::~XQServiceProvider_Private()
   417         // "mailto", etc. standard schemes.
   138 {
   418         //
   139     XQSERVICE_DEBUG_PRINT("XQServiceProvider_Private::~XQServiceProvider_Private");
   419         // (As mentioned in the documentation, some schemes are CURRENTLY handled specially,
   140     delete m_adaptor;
   420         // like "http" scheme uses QDesktopServices::openUrl).  
   141 }
   421         // 
   142 
   422         QUrl url("testto://authority?param1=value1&param1=value2"); 
       
   423 
       
   424         // The difference to the previous example is is how request is created
       
   425         // via application mgr.
       
   426 
       
   427         request = mAiwMgr.create(url);
       
   428         if (request == NULL)
       
   429         {
       
   430             // No handlers for the URI
       
   431             return;
       
   432          }
       
   433 
       
   434         // Set function parameters
       
   435         QList<QVariant> args;
       
   436         args << uri.toSring();
       
   437         request->setArguments(args);
       
   438 
       
   439         // Send the request
       
   440         bool res = request.send();
       
   441         if  (!res) 
       
   442         {
       
   443             // Request failed. 
       
   444             int error = request->lastError();
       
   445             // Handle error
       
   446         }
       
   447 
       
   448         // If making multiple requests to same service, you can save the request as member variable
       
   449         // In this example all done.
       
   450         delete request;
       
   451     \endcode
       
   452    
       
   453     <b>File viewer</b> \n
       
   454     As for URis, a service application that support viewing a file with a dedicated MIME-type need to publish support for:
       
   455     - The common interface "com.nokia.symbian.IFileView".
       
   456     - The slot "view(QString)" to view the non-data-caged file by file name.
       
   457     - The slot "view(XQSharable)" to view the data-caged file by sharable file handle.
       
   458     - MIME type list (registered in the .pro file).
       
   459     So there are multiple service applications implementing the same interface.
       
   460     
       
   461     In service provider side you need the following entry in XML:
       
   462     
       
   463     \code
       
   464         <interface>
       
   465             <name>com.nokia.symbian.IFileView</name>
       
   466             <version>1.0</version>
       
   467             <description>Interface for showing Files</description>
       
   468         </interface>
       
   469     \endcode
       
   470     
       
   471     The file viewer application shall offer slots both for viewing filename (QString) and viewing sharable file (XQSharable):
       
   472     
       
   473     \code
       
   474     class FileService : public XQServiceProvider
       
   475     {
       
   476         Q_OBJECT
       
   477         public:
       
   478             FileService( ServiceApp *parent = 0 );
       
   479             ~FileService();
       
   480             bool asyncAnswer() {return mAsyncAnswer;}
       
   481             void complete(bool ok);
       
   482 
       
   483         public slots:
       
   484             bool view(QString file);
       
   485             bool view(XQSharableFile file);
       
   486             
       
   487         private slots:
       
   488             void handleClientDisconnect();
       
   489 
       
   490         private:
       
   491             ServiceApp* mServiceApp;
       
   492             bool mAsyncAnswer;
       
   493             int mAsyncReqId;
       
   494             bool mRetValue;
       
   495     };
       
   496     \endcode
       
   497     
       
   498     In the .pro file the service publishes the supported MIME types, e.g:
       
   499     
       
   500     \code
       
   501         RSS_RULES += \
       
   502           "datatype_list = " \
       
   503           "      {" \
       
   504           "      DATATYPE" \
       
   505           "          {" \
       
   506           "          priority = EDataTypePriorityNormal;" \
       
   507           "          type = \"text/plain\";" \
       
   508           "          }" \
       
   509           "      };" \
       
   510     \endcode
       
   511     
       
   512     In the client side (see the "examples/appmgrclient" and "examples/serviceapp" included in the QtHighway release) access to
       
   513     file:
       
   514     
       
   515     \code
       
   516         // Not data caged file
       
   517         QFile file("C:\\data\\Others\\test.txt");
       
   518 
       
   519         request = mAiwMgr.create(file);
       
   520         if (request == NULL)
       
   521         {
       
   522                // No handlers for the URI
       
   523                return;
       
   524          }
       
   525         // By default operation is "view(QString)"
       
   526 
       
   527         // Set function parameters
       
   528         QList<QVariant> args;
       
   529         args << file.fileName();
       
   530         request->setArguments(args);
       
   531 
       
   532         // Send the request
       
   533         bool res = request.send();
       
   534         if  (!res) 
       
   535         {
       
   536            // Request failed. 
       
   537           int error = request->lastError();
       
   538 
       
   539           // Handle error
       
   540         }
       
   541      
       
   542         // If making multiple requests to same service, you can save the request as member variable
       
   543         // In this example all done.
       
   544         delete request;
       
   545     \endcode
       
   546     
       
   547     <b>Sharable file viewer</b> \n
       
   548     The same rules as for file name based view applies, but different argument type (XQSharableFile) used
       
   549     in request. See the "examples/appmgrclient" and "examples/serviceapp" included in the QtHighway release.
       
   550     
       
   551     \code
       
   552         XQSharableFile sf;
       
   553         // Open the file for sharing from own private  directory
       
   554         // If you have handle available, just set it by "setHandle()" function
       
   555         if (!sf.open("c:\\private\\e0022e74\\test.txt"))
       
   556         {
       
   557             // Failed to open sharable file
       
   558             return;
       
   559         }
       
   560 
       
   561         // Create request for the sharable file
       
   562         XQAiwreqiuest req = mAiwMgr.create(sf);
       
   563         if (!req)
       
   564         {
       
   565             // No viewer app found for the file
       
   566             // As we opened the handle, we need to close it !
       
   567             sf.close(); 
       
   568             return;  
       
   569         }
       
   570         // By default operation is "view(XQSharableFile)"
       
   571 
       
   572         // Set function parameters
       
   573         // Not only one sharable handle supported,  otherwise upon send EArgumentError error occurs
       
   574         QList<QVariant> args;
       
   575         args << qVariantFromValue(sf);  
       
   576         req->setArguments(args);
       
   577 
       
   578         // Send the request
       
   579         bool res = request.send();
       
   580         if  (!res) 
       
   581         {
       
   582             // Request failed. 
       
   583             int error = request->lastError();
       
   584             // Handle error
       
   585         }
       
   586 
       
   587         // As we opened the handle, we need to close it !
       
   588         sf.close(); 
       
   589 
       
   590         // If making multiple requests to same service, you can save the request as member variable
       
   591         // In this example all done.
       
   592         delete request;
       
   593     \endcode
       
   594     
       
   595     <b> Create interface action </b> \n
       
   596     One interface XML may offer one action to be displayed by client application.
       
   597     See the "examples/appmgrclient" and "examples/hbserviceprovider" included in the QtHighway release.
       
   598     
       
   599     \code
       
   600     HbAction* ShareUiPrivate::fetchServiceAction(XQAiwInterfaceDescriptor interfaceDescriptor)
       
   601         {
       
   602         QDEBUG_WRITE("ShareUiPrivate::fetchServiceAction start");
       
   603         // create the request for each descriptor.
       
   604         
       
   605         XQAiwRequest* request = mAppManager.create(interfaceDescriptor,SELECT_OP,false);
       
   606         QAction action = request->createAction());
       
   607         if (!action)
       
   608             return 0;
       
   609 
       
   610         // if Orbit widgets do not support QAction
       
   611         // Need to convert QAction to HbAction first
       
   612         HbAction* hbAction = convertAction(action);
       
   613         if(hbAction)
       
   614             {
       
   615             // Connect triggered signals to enable the request to emit triggered 
       
   616             connect(hbAction, SIGNAL(triggered()), action, SIGNAL(triggered()));
       
   617 
       
   618             // connect the request's triggered action to the slot in app
       
   619             connect(request, SIGNAL(triggered()), this, SLOT(onTriggered()));
       
   620             }
       
   621             
       
   622         return hbAction;
       
   623         }
       
   624     \endcode
       
   625     
       
   626     In service provider side you need to have the following entries in XML to be converted to QAction by the create:
       
   627     
       
   628     \code
       
   629         <interface>
       
   630             <name>Dialer></name>
       
   631             <version=1.0</version>
       
   632             <description>Dial interface</description>
       
   633             <customproperty key="aiw_action_text_file">hbserviceprovider</customproperty>
       
   634             <customproperty key="aiw_action_text">txt_aiw_action_text</customproperty>
       
   635         </interface>
       
   636     \endcode
       
   637 */
       
   638 
       
   639 /*!
       
   640     \fn void XQServiceProvider::returnValueDelivered()
       
   641     
       
   642     This signal is emitted when asynchronous request has been completed and its
       
   643     return value has been delivered to the service client.
       
   644 */
       
   645 
       
   646 /*!
       
   647     \fn void XQServiceProvider::clientDisconnected()
       
   648     
       
   649     This signal is emitted if client accessing a service application terminates.
       
   650     The counterpart in client side (when service application terminates) is
       
   651     the error XQService::EConnectionClosed.
       
   652 */
   143 
   653 
   144 /*!
   654 /*!
   145     Construct a remote service object for \a service and attach it to \a parent.
   655     Construct a remote service object for \a service and attach it to \a parent.
       
   656     \param service Defines the full service name that is implemented. 
       
   657                    The full service name is:
       
   658                    - The name of the service from the service configuration file
       
   659                    - Character *.* (dot)
       
   660                    - The name of the interface from the service configuration file
       
   661     \param parent Parent of this QObject
   146 */
   662 */
   147 XQServiceProvider::XQServiceProvider( const QString& service, QObject *parent )
   663 XQServiceProvider::XQServiceProvider( const QString& service, QObject *parent )
   148     : QObject( parent )
   664     : QObject( parent )
   149 {
   665 {
   150     XQSERVICE_DEBUG_PRINT("XQServiceProvider::XQServiceProvider");
   666     XQSERVICE_DEBUG_PRINT("XQServiceProvider::XQServiceProvider");
   153     connect(m_data->m_adaptor, SIGNAL(returnValueDelivered()), this, SIGNAL(returnValueDelivered())); 
   669     connect(m_data->m_adaptor, SIGNAL(returnValueDelivered()), this, SIGNAL(returnValueDelivered())); 
   154     connect(m_data->m_adaptor, SIGNAL(clientDisconnected()), this, SIGNAL(clientDisconnected())); 
   670     connect(m_data->m_adaptor, SIGNAL(clientDisconnected()), this, SIGNAL(clientDisconnected())); 
   155 }
   671 }
   156 
   672 
   157 /*!
   673 /*!
   158     Destroy this service handling object.
   674     Destroys this service handling object.
   159 */
   675 */
   160 XQServiceProvider::~XQServiceProvider()
   676 XQServiceProvider::~XQServiceProvider()
   161 {
   677 {
   162     XQSERVICE_DEBUG_PRINT("XQServiceProvider::~XQServiceProvider");
   678     XQSERVICE_DEBUG_PRINT("XQServiceProvider::~XQServiceProvider");
   163     if (m_data)
   679     if (m_data)
   185         m_data->m_adaptor->publishAll(m_data->plugin, 0, XQServiceAdaptor::Slots);
   701         m_data->m_adaptor->publishAll(m_data->plugin, 0, XQServiceAdaptor::Slots);
   186     } 
   702     } 
   187 }
   703 }
   188 
   704 
   189 /*!
   705 /*!
   190 *   Sets current request to asynchronous mode so that provider can complete the
   706     Sets current request to asynchronous mode so that provider can complete the
   191 *   request later via the completeRequest() call. 
   707     request later via the completeRequest() call.
   192 *   \return Request ID which shall be used in the completeRequest() call.
   708     \return Request ID which shall be used in the completeRequest() call.
       
   709     \note There can be several clients accessing the same service at the same time. Avoid saving
       
   710           the index to XQServiceProvider instance as member variable as when another new request
       
   711           comes in, it will have different index and you will potentially override the index of
       
   712           the first request. You should ensure the completeRequest() gets the correct index e.g.
       
   713           by attaching the index as user data to data object maintain a map of indexes based on
       
   714           some key.
   193 */
   715 */
   194 int XQServiceProvider::setCurrentRequestAsync()
   716 int XQServiceProvider::setCurrentRequestAsync()
   195 {
   717 {
   196     XQSERVICE_DEBUG_PRINT("XQServiceProvider::setCurrentRequestAsync");
   718     XQSERVICE_DEBUG_PRINT("XQServiceProvider::setCurrentRequestAsync");
   197     return m_data->m_adaptor->setCurrentRequestAsync();
   719     return m_data->m_adaptor->setCurrentRequestAsync();
   198 }
   720 }
   199 
   721 
   200 /*!
   722 /*!
   201 *   Completes the asynchronous request with the given value
   723     \fn bool XQServiceProvider::completeRequest(int index, const T& retValue)
   202 *   \param index Request ID got from the setCurrentRequestAsync call.
   724     
   203 *   \param retValue The value
   725     Completes asynchronous request.
   204 *   \return true on success, false if index points to non-existing request.
   726     \param index Defines the index of the asynchronous request to complete. 
       
   727     \param retValue defines the return value for the request.
       
   728     \return true if request could be completed successfully, otherwise false.
       
   729     \sa completeRequest()
       
   730 */
       
   731 
       
   732 /*!
       
   733     Completes the asynchronous request with the given value
       
   734     \param index Request ID got from the setCurrentRequestAsync call.
       
   735     \param retValue Returned value.
       
   736     \return true on success, false if index points to non-existing request.
       
   737     \note <b>You need to check the return value. </b>
       
   738           If false it means connection to client has been lost and the complete will not ever succeed. 
       
   739           So if you have e.g. a code that quits application using the ReturnValueDelived signal only,
       
   740           that signal will never be emitted as request can not be completed.
   205 */
   741 */
   206 bool XQServiceProvider::completeRequest(int index, const QVariant& retValue)
   742 bool XQServiceProvider::completeRequest(int index, const QVariant& retValue)
   207 {
   743 {
   208     XQSERVICE_DEBUG_PRINT("XQServiceProvider::completeRequest");
   744     XQSERVICE_DEBUG_PRINT("XQServiceProvider::completeRequest");
   209     XQSERVICE_DEBUG_PRINT("index: %d, retValue: %s", index, qPrintable(retValue.toString()));
   745     XQSERVICE_DEBUG_PRINT("index: %d, retValue: %s", index, qPrintable(retValue.toString()));
   210     return m_data->m_adaptor->completeRequest(index, retValue);
   746     return m_data->m_adaptor->completeRequest(index, retValue);
   211 }
   747 }
   212 
   748 
   213 /*!
   749 /*!
   214 *   Return additional request information attached to  request
   750     Return additional request information attached to request
   215 *   \return Request info
   751     \return Request info.
   216 */
   752 */
   217 XQRequestInfo XQServiceProvider::requestInfo() const
   753 XQRequestInfo XQServiceProvider::requestInfo() const
   218 {
   754 {
   219     return m_data->m_adaptor->requestInfo();
   755     return m_data->m_adaptor->requestInfo();
   220 }
   756 }