/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Free Documentation License
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of this
** file.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!
    \group servicefw
    \title Service Frameworks Classes

    A set of APIs to that allows clients to discover and instantiate
arbitrary services.

*/


/*!
\page service-frameworks.html

\title Qt Service Framework

\brief A set of Qt APIs to that allows clients to discover and instantiate
arbitrary services.

\ingroup mobility

The Qt Service Framework allows clients to discover and instantiate
arbitrary services.


\tableofcontents

\section1 Namespace

The QtMobility APIs are placed into the \i{QtMobility} namespace. This is done
to facilitate the future migration of QtMobility APIs into Qt. See the
\l {Quickstart guide} for an example on how the
namespace impacts on application development.


\section1 Introduction

The Qt Service Framework defines a unified way of finding, implementing and
accessing services across multiple platforms.

Due to the service frameworks knowledge of service interfaces, their
versions and QObject-based introspection it may even be used to unify and
access multiple platform specific service implementations via the same
Qt-based client application.

\section1 Overview

A service is an independent component that allows a client to perform a
well-defined operation. Clients can find services based on their name and
version as well as the interface that is implemented by the service object.
Once the service has been identified the framework starts the service and
returns a pointer to it. QServiceManager is the main interface through
which clients can access the mentioned framework functionality. In
addition services themselves may also act as clients to the service
framework by requesting other services installed on the system.

Service provider are implemented via plug-ins. QServicePluginInterface
defines the main interface for each plug-in.
In order to avoid that clients have to link against service specific
libraries each service object must be derived from QObject. Therefore the
QMetaObject system can be used to dynamically discover and invoke the
service's capabilities.
To achieve the best level of access via the Qt meta object system services
should be implemented in such a way that their entire functionality is
accessible via the signals, slots, properties or invokable functions
(see Q_INVOKABLE macro for more details).

Each service plug-in implements one service only but can provide multiple
implementations for multiple interfaces.
Therefore a service (plug-in) can retain a certain level of backwards
compatibility even if the main service interface breaks in such a way that
a new interface name has to be used. Existing clients can still use the
previous version of service interface whereas new clients can utilize the
new interface.

Services can also include remote processes.  By registering with the
service manager processes can communicate via signals, slots,
invokable functions and properties as if they were local objects.
Services can choose to be either shared between all clients, or
unique to that client.


\section1 Using the Framework

This section assumes that the user wants to access the \i FileStorage
service which offers an implementation for the \i com.nokia.qt.examples.FileStorage
interface The service framework enables multiple ways of accessing those
implementations.

QServiceManager is the main class to lookup and instantiate services.
Services can be found by constraining the search via service meta data or
by using the default lookup mechanism.

\section2 Verbose Lookup

The client code has precise knowledge of the service and its interfaces.

\code
    QServiceManager manager;
    QServiceFilter filter("com.nokia.qt.examples.FileStorage");
    filter.setServiceName("FileStorage");

    // find services complying with filter
    QList<QServiceInterfaceDescriptor> foundServices;
    foundServices = manager.findInterfaces(filter);
    Q_ASSERT(foundServices.count());

    // instantiate the FileStorage object
    QObject *fileStorage;
    fileStorage = manager.loadInterface(foundServices.at(0));
\endcode

\section2 Default Lookup

It is assumed that the client has knowledge of the interface but does not really care
about the specific type or version of the service implementing the interface. In such cases the default
service lookup can be utilized to create a service object instance.

\code
    QServiceManager manager;
    manager.setInterfaceDefault("FileStorageService", "com.nokia.qt.examples.FileStorage");
\endcode

The above call to \l QServiceManager::setInterfaceDefault() registers the \i FileStorageService as default implementation.
Whenever a client asks for an implementation of \i com.nokia.qt.examples.FileStorage the \i FileStorageService
service will be loaded. If (at the time of this call) the \i FileStorageService provides multiple registered implementations/versions for the
same interface the latest version becomes the default. Therefore subsequent versions of the same interface
must always be binary compatible to previous versions.

The current scope of the service manager object determines whether the default assignment is valid for all users
or whether it is valid for the current user only. The system default is used if the user
scope has not been defined. This enables users to customize their personal preferences.
By default the first service installing a so far unknown interface becomes the system wide default selection.

\section3 \bold{QObject based services}

This is the most common way of interacting with services.

\code
    storage = manager.loadInterface("com.nokia.qt.examples.FileStorage");
    if (storage)
        QMetaObject::invokeMethod(storage, "deleteFile", Q_ARG(QString, "/tmp/readme.txt"));
\endcode

The above invocation of the file storage object's deleteFile() function is done via the service's
QMetaObject. The client does not require any knowledge of the objects actual type and therefore
does not have to link against a service specific library.

\section3 \bold{Typed services}

So far all lookup mechanism returned a QObject pointer. This pointer can be
utilized by introspecting the object, using Qt's meta object system.
However in some use cases it may be more convenient to
directly interact with the service object by including the service header
and/or linking against the service provider. The main advantage is compile time checking.
Its disadvantage is that client and service must share the implementation of the service object via a library
they link against or via a common header file. Note that such sharing breaks the fundamental ServiceFramework
principle of separating clients from service as changes of the service type may require changes to both, services and clients.

The subsequent code snippet demonstrates how this may look like:

\code
    #include <filestorage.h>
    ...
    QServiceManager manager;
    FileStorage *storage = 0;
    ...
    storage = manager.loadLocalTypedInterface<FileStorage>("com.nokia.qt.examples.FileStorage");
    if (storage)
        storage->deleteFile("/tmp/readme.txt");
\endcode


\section1 Service Scope

The QServiceManager operates in either \l{QService::UserScope}{User scope}
or \l{QService::SystemScope}{System scope}. By default, it operates
in user scope. The choice of scope affects whether registered services are
available system-wide or only to the current user, and whether service and
interface lookups are limited to system-wide service or whether the current
user's together with system service configurations are considered.

\section2 User Scope

In user scope, services are registered in a storage location specific to
the current user. When a default service is set for an interface using
\l{QServiceManager::setInterfaceDefault()}{setInterfaceDefault()}, the
referenced service can be either a user-specific or system-wide service.

For service and interface lookups, a manager will first search the
user-specific services; if the requested component is not found, the
manager then searches the system-wide services, if the user has
sufficient permissions to do so.

The \l{QServiceManager::serviceAdded()} and \l{QServiceManager::serviceRemoved()}
notifications are emitted when services are added or removed from either
the user-specific or system-wide services. These signals have a \c scope
parameter to indicate the scope in which the service was added or removed.
(Note the system-wide service notifications are only available if the user
has sufficient permissions to access the system-wide service storage.)

\section2 System Scope

In system scope, services are registered in a system-wide storage location.
The manager does not access user-specific services for any operations.
Service and interface lookups fail if the requested services are not found
in the system-wide service storage. Service registration is performed in
the system-wide storage.

If \l{QServiceManager::setInterfaceDefault()}{setInterfaceDefault()} is
called for a user-specific service, the operation fails.

Also, the \l{QServiceManager::serviceAdded()} and \l{QServiceManager::serviceRemoved()}
notifications are only emitted for system-wide services.



\section1 Adding and Removing of Services

New services can be installed and removed at runtime. An XML file is used
to describe the service meta data and links the service code to its meta
description.

\section2 XML Format

Services are installed via an XML file which describes the meta data and
location of the service. The XML file can be described via the following
DTD:

\code
    <!ELEMENT SFW ( service ) >
    <!ATTLIST SFW version (1.0|1.1) #REQUIRED >
    <!ELEMENT service ( name, filepath | ipcaddress, description?, interface+ ) >
    <!ELEMENT description ( #CDATA ) >
    <!ELEMENT filepath ( #PCDATA ) >
    <!ELEMENT ipcaddress ( #PCDATA ) >
    <!ELEMENT interface ( name, version, description?, capabilities?, customproperty* ) >
    <!ELEMENT capabilities ( #PCDATA ) >
    <!ELEMENT name ( #PCDATA ) >
    <!ELEMENT version ( #PCDATA ) >
    <!ELEMENT customproperty ( #CDATA ) >
    <!ATTLIST customproperty key NMTOKEN #REQUIRED >

\endcode

The elements and attributes have the following meanings:

\table
    \header
        \o Element \o SubElement \o Description
    \row
        \o SFW
        \o
        \o The service framework XML version tag that encapsulates the service XML. Must provide the
           version attribute that follows the \i major.minor notation and must equate to supported
           Qt Service Framework versions. This means the minimum version is 1.0 however users are
           recommended to always specify the highest available version.
    \row
        \o service
        \o
        \o The \i service tag can contain an arbitrary number of \i interface tags and one description tag.
    \row
        \o "
        \o description
        \o A user readable description of the purpose of the service.
    \row
        \o "
        \o filepath
        \o The absolute path and name of the plug-in to be loaded when this
           service is requested. Alternatively if the plug-in name only is
           provided the standard library paths (see QCoreApplication::libraryPaths())
           are used to find the plug-in.
           Note that if the plugin name is given only, platform specific
           parts such as the suffix ".dll" and ".so" or plugin prefix "lib"
           should be removed to enable cross platform resolution. QLibrary
           is used to determine the platform specific parts of the plugin.
    \row
        \o "
        \o ipcaddress
        \o The socket name or path that the inter-process service will be published
           on that will provide clients with remote access. Should be the same name
           as the executable for the service without any suffix such as ".exe" etc.
    \row
        \o "
        \o name
        \o The name of the service.
    \row
        \o interface
        \o
        \o The \i interface describes the properties of the interface.
    \row
        \o "
        \o capabilities
        \o This property is a list of arbitrary strings which are
           interpreted as permissions/capabilities. The list elements are
           comma-separated and spaces after commas are not permitted.
           This list can be empty.
    \row
        \o "
        \o name
        \o The name of the interface using the Java class name notation. (e.g. com.nokia.qt.TestService)
    \row
        \o "
        \o version
        \o This property contains the interface and implementation version.
        The version tag follows the \i major.minor notation. The major
        version indicates the interface version the minor version the
        implementation version.

           The version number \bold must be greater than 1.0. The version
           cannot be less than 1.0 because the Service Framework is
           dependent on the fact that services must be binary compatible
           between major versions, and services with versions less than 1.0
           are unlikely to be binary compatible with later versions.
    \row
        \o "
        \o description
        \o A user readable description of the purpose of the interface.
    \row
        \o "
        \o customproperty
        \o An implementation specific key value pair which can be used for
        filtering or as description.

\endtable


An example for a valid XML service description could be the following \i TestService:

\code
    <?xml version="1.0" encoding="utf-8" ?>
    <SFW version="1.1">
    <service>
        <name>TestService</name>
        <filepath>testserviceplugin</filepath>
        <description>Test service description</description>
        <interface>
            <name>com.nokia.qt.ILocation</name>
            <version>1.4</version>
            <capabilities></capabilities>
            <description>Interface that provides location support</description>
        </interface>
        <interface>
            <name>com.nokia.qt.ILocation</name>
            <version>1.5</version>
            <capabilities></capabilities>
            <description>Interface that provides location support</description>
        </interface>
        <interface>
            <name>com.nokia.qt.ISysInfo</name>
            <capabilities>ReadUserData</capabilities>
            <version>2.3</version>
            <description>Interface that provides system information support</description>
            <customproperty key="key1">value1</customproperty>
            <customproperty key="key2">value2</customproperty>
        </interface>
    </service>
    </SFW>
\endcode

\section1 Tools for XML Generation

The framework includes a GUI tool under \tt tools/servicexmlgen for
generating and inspecting service XML files. This makes it easy to enter
service metadata and interface details and generate the appropriate XML to
describe the plugin or IPC based service. It can also be used to load and
inspect existing service XML files.

Note that the tool will default to the highest known existing Qt Service Framework
version as the XML version attribute and subsequent saves on loaded files will
enforce this default version.

Here is a screenshot of the application, loaded with the \i TestService XML
description provided above.

\image servicexmlgen.png


\section1 Installing the Service at Runtime

New services can be added and removed at any time via QServiceManager::addService()
and QServiceManager::removeService().

On Symbian devices a service can be installed using the Symbian package installer. More
details about this process can be found in the \l {Qt Service Framework on Symbian} documentation.


\section1 Identifying Services

Each implementation is identified by a service name, an interface name and
its version. This information is encapsulated by
QServiceInterfaceDescriptor which can be used to request references to
service objects.

QServiceFilter simplifies the lookup of already installed services.
Developers specifies the criteria used during the meta data lookup.
The subsequent example demonstrates the interaction between
QServiceInterfaceDescriptor and QServiceFilter by creating references to
all services that implement the interface \i com.nokia.qt.ILocation:

\code
    QServiceManager mgr;
    QServiceFilter filter;
    filter.setInterface("com.nokia.qt.ILocation");
    QList<QServiceInterfaceDescriptor> list = mgr.findInterfaces(filter);
    for(int i = 0; i < list.size(); i++) {
        QObject *serviceObject;
        serviceObject = mgr.loadInterface(list[i]);

        // returned object owned by client
        if (serviceObject)
            serviceObject->setParent(this);
    }
\endcode

\section2 Upgrading Services

There are two ways in which to upgrade a service.  The first is an
incremental approach whereby QServiceManager::addService() is used to
register an XML descriptor whose service name already exists but defines
new interface implementations.  For example an already existing service,
"ovi" may define version 1.0 of interface,"IDownload".
QServiceManager::addService() is then called with an XML descriptor that
declares itself as belonging the "ovi" service, but implements version 1.1
of the interface "IDownload".  Both implementation versions will be
available for use.

The second method is a replacement approach whereby an existing service is
completely removed and replaced by a new service.

As an example the already existing "ovi" service may implement interface
"IDownload" version 1.0, the new "ovi" service may implement "IDownload"
version 1.0 and version 1.1.  In this case the old service implementation
must be first be removed using QServiceManager::removeService() to make
way for the new service implementation.

\section1 Out of Process Services

Qt Service Framework provides a mechanism for out of process services
so that clients can remotely load interfaces.  These inter-process
services are deployed similarly to local services, using the IPC address
tag from the XML description and calling QRemoteServiceRegister::publishEntries()
to add the service to the remote services manager. Clients access services
via the metaobject similarly to in-process services and each remote service
is represented as a QRemoteServiceRegister::Entry by using
QRemoteServiceRegister::createEntry(). The \l{Echo Client Example} demonstrates
how remote services can be instantiated and used.

Inter-process services are deployed using a variety of different IPC mechanisms
available on the current platform and as such may inherit several limitations.  For
Symbian, IPC is handled by the Symbian Client-Server Framework whereas for other
environments services are published using QtDBus if it is available otherwise
falls back on QLocalSocket for inter-process communication.

\section2 D-Bus Services

The QtDBus module is used to provide IPC in correspondance to the Qt Service
Framework architecture and provides access to signals, slots, invokable methods
and properties.

The D-Bus protocol requires concept identifiers that represent D-Bus objects:
service names, object paths, and interfaces. D-Bus objects are registered using
a combination of the service description supplied in the service XML file. An
example of this, using the previous sample XML description, is provided below.

\table 90%
\header \o D-Bus Concept  \o Derived Name
\row    \o Service Name   \o "com.qtmobility.sfw.TestService"
\row    \o Object Path    \o "/com/nokia/qt/ILocation/1/4/"
\row    \o Interface      \o ""
\endtable

\section3 Limitations

A current known limitation for Qt Service Framework using QtDBus for IPC is
that enumerators cannot be read due to lack of support on D-Bus.  This will be
added in future versions once the QtDBus module enables enumerator support. A
current known workaround is to manually define and use integers as demonstrated
in the \l{Service Framework using QML Example}{Declarative Serviceframework
Dialer} example. Furthermore, due to the nature of IPC, pointers to objects
cannot be passed between services and clients.  Unfortunately, this also means
that anything wrapped in a typedef macro cannot be communicated effectively
between processes.

\section3 Service Autostart
D-Bus services inherit automatic start support by providing .service files to the
D-Bus daemon search paths. Aside from producing these files manually, the
servicefw tool provides an option to generate the corresponding files inside
the local user D-Bus folder for convenience. This will allow all client
requests to automatically startup the service if it isn't already running.
Consequently, once every client has closed its service instance the service will
be automatically terminated after invoking any slots connected to notification signals.

Running the following command will enable rendezvous for D-Bus IPC.

\code
./servicefw dbusservice <service-xml-file> <service-file>
\endcode

The .service files will typically be generated in the $home/.local/share/dbus-1/services
directory unless the $$XDG_DATA_HOME environment variable is set. If the --system
option is used the tool will generate the file inside /usr/share/dbus-1/services if
the user permissions are met.

Note that in order for the autostart feature to function correctly, the service
needs to be either pre-registered or registered at run-time so that clients can use
a QServiceManager to discover the IPC interfaces that invoke the D-Bus service files.
This is usually done on deployment by adding services through the servicefw tool.


\section2 Symbian Client-Server Framework

\section3 Limitations
Pointers to objects, and anything wrapped in a typedef cannot be passed
between services and clients.  It's recommended that IPC messages
be kept small on Symbian when possible.  Symbian Client-Server IPC mandates
a fixed buffer size, currently set at 255 bytes. Messages that are large
will cause a large number of context switches. This may cause a system
performance pentalty if a lot of very large messages are transfered frequently.

\section3 Service Autostart
Symbian IPC will automatically start the server process if required when the client
calls loadInterface.  The executable name must be the same as the name provided
<ipcaddress> tag in the xml registration file.  For example <ipcaddress>xyzabc</ipcaddress>
should have the executable for the service called xyzabc.exe.

\section3 Service registration
All services must be registered for clients to be able to locate and use them.
Symbian provides 3 different methods to register services.

\list
\o \l{Automatic registration}
\o \l{Secure registration}
\o \l{ROM build registration}
\endlist

\section4 Automatic Registration
Automatic registration is the prefered method for services that are not
Symbian Signed and don't require high levels of security.  The XML
file is copied into the import directory of the IPC backend.  In Qt
project files this can be done by:

\code
xmlautoimport.path = /private/2002AC7F/import/
xmlautoimport.sources = <service xml file>.xml
DEPLOYMENT += xmlautoimport
\endcode

Or in a symbian .pkg file by:

\code
"/epoc32/data/z/private/2002AC7F/import/<service xml file>.xml" - "c:\private\2002AC7F\import\<service xml file>.xml"
\endcode

\section4 Secure Registration
For services that are Symbian Signed and require a higher level of security they
may chose to use a post install program.  The authenticity check of the service is done during
registration using the VID/SID.  If the installer defines the VID it is stored in the
registration database, and only the same VID maybe used to remove the service or reinstall it.
If the VID is undefined then the SID is used.  The VID/SID remain in the registration
database after unregistration locking the name to the VID/SID.  Only installers using the
same VID/SID may register a service of the same name.

An example project can be found at \c {examples/serviceinstaller_sfw_symbian}.

More info about VID and SID can be found from
\list
    \o \l {http://wiki.forum.nokia.com/index.php/Symbian_Platform_Security_Model}
    \o \l {http://wiki.forum.nokia.com/index.php/Symbian_Signed_Test_Criteria_V4_Wiki_version}
\endlist

\section4 ROM build registration
For Symbian application built into the rom image registration must be done at
build time using the host tool servicedbgen. To register a service run
the command:

\code
servicedbgen -tall add <service xml file>
\endcode

Appropriate iby files, and settings are required for including the service executable
and related files in the rom image.

\section3 Service Security Filters
Services can install a filter function to check the credentials
of a client on initial connection and then terminate connections if desired.
The filter is a function:

\code
bool securityFilter(const void *p)
{
    const RMessage2 *aMessage = reinterpret_cast<const RMessage2*>(p);
    if(check_security) {
        return true; // accept connection
    }
    else {
        retun false; // reject connection
    }
}
\endcode

Returning true returns CPolicyServer::EPass and false returns CPolicyServer::EFail
to the Client-Server secuity check.  Registration of the filter is done by
calling QRemoteServiceRegister::setSecurityFilter().  The Symbian Policy Server
API can be used to work with the RMessage2 to extract security policy details, such
as RMessage2::HasCapability or RMessage2::VendorId().

\section3 Error handling
IPC errors can occur. QObjects returned by the service manager have an additional
signal created, errorUnrecoverableIPCFault(QService::UnrecoverableIPCError) which the
client must connect to.  If an error occurs the object must be
destroyed; no further calls can be made.  The error recovery is left up to
the client application.

\section2 Local Socket

On platforms that do not provide D-Bus or the Symbian Client-Server Framework, the
underlying IPC mechanism utilized is a local socket based protocol.

\section3 Limitations
Similar to the other IPC mechanisms, passing object pointers or typedefs will not
work on local socket. Local socket also requires the executable for the service to
be installed somewhere in your PATH for autostart to work.  Not all platforms support
all fields on the QRemoteServiceResgiterCredentials and will return -1 in unsupported
fields.

\section3 Service Autostart
This mechanism provides automatic service startup. The <ipcaddress> tag
must be set to the executable filename.  For example
<ipcaddress>xyzabc</ipcaddress> must be used if the executable is xyzabc,
or xyzabc.exe on windows systems.  The PATH is searched for the executable.
If the executable is not found, or the service does not start, then
the error is reported to the client.

\section3 Service Registration
All services must be registered.  The 'servicefw' tool registers xml
files.  It must be run before a service can be used. For example:

\code
servicefw add <service xml file>
\endcode

\section3 Service Security Filters
The service can install a security filter to reject connections from
some clients. This applies to D-Bus and local socket implementations of IPC.

\code
bool securityFilter(const void *p)
{
    const QRemoteServiceRegisterCredentials *cr = (const struct QRemoteServiceRegisterCredentials *)p;
    if(cr->uid == 0) {
        return true; // accept connection
    }
    else {
        retun false; // reject connection
    }
}

struct QRemoteServiceRegisterCredentials {
    int fd;
    int pid;
    int uid;
    int gid;
};
\endcode

Returning true accepts the connect, false terminates it.  Certain
platforms do not provide all the results, and undefined values are
set to -1. Registration of the filter is done by
calling QRemoteServiceRegister::setSecurityFilter().  Only 1 filter maybe installed
at one time.

\section2 Error handling
Out of process services behave similarly to local services, with one
exception.  There can be IPC errors, or the remote service can
terminate unexpectedly.  QObjects returned by the service manager for
out of process services have an additional signal created,
errorUnrecoverableIPCFault(QService::UnrecoverableIPCError) which the
client must connect to.  If an error occurs the object must be
destroyed; no further calls can be made.  The error recovery is left up to
the client application.


\section1 Main Classes
\annotatedlist servicefw


\section1 QML Elements

The Qt Service Framework offers discovery and selection of services through declarative
UI by providing service and service list elements. Detailed information can be found
at \l{QML Service Framework Plugin}.

\annotatedlist qml-serviceframework


\section1 Examples
\list
    \o \l{Service Browser Example}
    \o \l{File Manager Plugin Example}
    \o \l{Bluetooth Transfer Plugin Example}
    \o \l{Notes Manager Plugin Example}
    \o \l{Notes Manager Example}
    \o \l{Echo Client Example}
    \o \l{declarative-sfw-notes}{Declarative Notes Manager}
    \o \l{declarative-sfw-dialer}{Declarative Serviceframework Dialer}
\endlist

*/
