/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** 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. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $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 technology-apis

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

\tableofcontents

\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 Getting Started

To load the Qt Service Framework module into your .qml files, add the following

\qml
    import QtServiceFramework 5.0
\endqml

For C++ files you will need to add the directive

\code
    #include <QtServiceFramework>
\endcode

And for linking against the module add this to your qmake .pro file

\code
    QT += serviceframework
\endcode

\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 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 \e FileStorage
service which offers an implementation for the \e 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 \e FileStorageService as default implementation.
Whenever a client asks for an implementation of \e com.nokia.qt.examples.FileStorage the \e FileStorageService
service will be loaded. If (at the time of this call) the \e 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 \b{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 \b{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
        \li Element \li SubElement \li Description
    \row
        \li SFW
        \li
        \li The service framework XML version tag that encapsulates the service XML. Must provide the
           version attribute that follows the \e 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
        \li service
        \li
        \li The \e service tag can contain an arbitrary number of \e interface tags and one description tag.
    \row
        \li "
        \li description
        \li A user readable description of the purpose of the service.
    \row
        \li "
        \li filepath
        \li 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
        \li "
        \li ipcaddress
        \li 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
        \li "
        \li name
        \li The name of the service.
    \row
        \li interface
        \li
        \li The \e interface describes the properties of the interface.
    \row
        \li "
        \li capabilities
        \li 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
        \li "
        \li name
        \li The name of the interface using the Java class name notation. (e.g. com.nokia.qt.TestService)
    \row
        \li "
        \li version
        \li This property contains the interface and implementation version.
        The version tag follows the \e major.minor notation. The major
        version indicates the interface version the minor version the
        implementation version.

           The version number \b 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
        \li "
        \li description
        \li A user readable description of the purpose of the interface.
    \row
        \li "
        \li customproperty
        \li 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 \e 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 \e 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().

\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 \e 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 remote dialer service example
demonstrates using a out of process service.

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
some linux environments services can published using QtDBus otherwise it
falls back on QLocalSocket for inter-process communication.

\section2 D-Bus Services

The QtDBus module is used to provide IPC in correspondence 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 \li D-Bus Concept  \li Derived Name
\row    \li Service Name   \li "com.qtmobility.sfw.TestService"
\row    \li Object Path    \li "/com/nokia/qt/ILocation/1/4/"
\row    \li Interface      \li ""
\endtable

\section3 Limitations

When using integer types for arguments to signals and slots,
bass types as defined by http://doc.qt.nokia.com/4.7/qdbustypesystem.html.
For example, quint64 is generally equivalent to qulonglong, but
all unsigned 64 bit values must be defined as qulonglong or they will
not work with the dbus implementation. For more details and the current
state of the limitation please refer to bug
\l {http://bugreports.qt.io/browse/QTMOBILITY-1694}{QTMOBILITY-1694}.

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 Local Socket

On platforms that do not provide D-Bus or do not use it, 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 QRemoteServiceRegisterCredentials 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

Service objects can filter the clients that are allowed to connect to them.
This is done by creating an invokable constructor that has a
QServiceClientCredentials as its first and only paramter. For example:

\code
class ExampleService : public QObject
{
    Q_OBJECT
public:
    ExampleService(QObject* parent = 0)
        : QObject(parent)
    {
        // this constructor will not be called
    }

    Q_INVOKABLE ExampleService(QServiceClientCredentials *creds)
        : QObject(0)
    {
        if (creds->getUserIdentifier() == 0)
            creds->setClientAccepted(true);
        else
            creds->setClientAccepted(false);
    }
};
\endcode

The new invokable constructor will be called instead of the default
constructor. Client credentials are passed in via the QServiceClientCredetials
class. If the client wishes to authorize the connection it must call either
setClientAccepted(true) or call setClientAccepted(false) to reject the client.
If the client is rejected the constructor should return immediatly, and object
will be destroyed.

If the object is a global object multiple clients can connect to the same
object. On construction the secure constructor will be called. For subsequent
client connections the invokable method "void
verifyNewServiceClientCredentials(QServiceClientCredentials *creds)"
will be called to authenticate new client connections. For example a global
class maybe defined as:

\code
class GlobalService : public QObject
{
    Q_OBJECT
public:
    GlobalService(QObject* parent = 0)
        : QObject(parent)
    {
        // this constructor will not be called
    }

    Q_INVOKABLE GlobalService(QServiceClientCredentials *creds)
        : QObject(0)
    {
        if (creds->getUserIdentifier() == 0)
            creds->setClientAccepted(true);
        else
            creds->setClientAccepted(false);
    }

    Q_INVOKABLE void verifyNewServiceClientCredentials(QServiceClientCredentials *creds)
    {
        if (creds->getUserIdentifier() == 0)
            creds->setClientAccepted(true);
        else
            creds->setClientAccepted(false);
    }
};

\endcode

For global objects, when the first client connects the secure
constructor is called. Subsequent connections will result in
the verifyNewServiceClientCredentials being called. When the
last client disconnected the object will be destroyed, and
the constructor will be called when the next client connects.

\section3 Service Security Filters
The service can install a security filter to reject connections from
some clients on initial connection. Service security described above allows
this to be controlled per object.  This is implemented on D-Bus and
local socket implementations of IPC.

\code
void securityFilter(QServiceClientCredentials *creds)
{
    if (creds->getUserIdentifier() == 0) {
        creds->setClientAccepted(true);  // accept the connection
    } else {
        creds->setClientAccepted(false); // reject the connection
    }
}

\endcode

By calling QServiceClientCredentials::setClientAccepted the connection
can be terminated or accepted.  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
    \li \l{dialer}{Declarative Serviceframework Dialer}
\endlist

*/
