summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlex <qt-info@nokia.com>2011-06-15 19:14:16 +1000
committerAlex <qt-info@nokia.com>2011-06-17 17:31:52 +1000
commit0e3be465c935700019f6232f88381613d51776d7 (patch)
treee2a44eda69ebd38183ea251532e0da9fcb6020a6 /src
parent79ec22e9cd8ef8f679c541c4fd76d616e737b8bf (diff)
Add first version of QtServiceFramework library
Diffstat (limited to 'src')
-rw-r--r--src/serviceframework/databasemanager.cpp914
-rw-r--r--src/serviceframework/databasemanager_p.h140
-rw-r--r--src/serviceframework/databasemanager_symbian.cpp541
-rw-r--r--src/serviceframework/databasemanager_symbian_p.h183
-rw-r--r--src/serviceframework/databasemanagerserver_symbian/clientservercommon.h80
-rw-r--r--src/serviceframework/databasemanagerserver_symbian/databasemanagerserver.cpp229
-rw-r--r--src/serviceframework/databasemanagerserver_symbian/databasemanagerserver.pan58
-rw-r--r--src/serviceframework/databasemanagerserver_symbian/databasemanagerserver.pro43
-rw-r--r--src/serviceframework/databasemanagerserver_symbian/databasemanagerserver_p.h111
-rw-r--r--src/serviceframework/databasemanagerserver_symbian/databasemanagerservermain.cpp69
-rw-r--r--src/serviceframework/databasemanagerserver_symbian/databasemanagersession.cpp614
-rw-r--r--src/serviceframework/databasemanagerserver_symbian/databasemanagersession_p.h112
-rw-r--r--src/serviceframework/databasemanagerserver_symbian/databasemanagersignalhandler.cpp56
-rw-r--r--src/serviceframework/databasemanagerserver_symbian/databasemanagersignalhandler_p.h68
-rw-r--r--src/serviceframework/dberror.cpp84
-rw-r--r--src/serviceframework/dberror_p.h104
-rw-r--r--src/serviceframework/ipc/instancemanager.cpp247
-rw-r--r--src/serviceframework/ipc/instancemanager_p.h105
-rw-r--r--src/serviceframework/ipc/ipc.pri46
-rw-r--r--src/serviceframework/ipc/ipcendpoint.cpp76
-rw-r--r--src/serviceframework/ipc/ipcendpoint_p.h78
-rw-r--r--src/serviceframework/ipc/metaobjectbuilder.pri12
-rw-r--r--src/serviceframework/ipc/objectendpoint.cpp636
-rw-r--r--src/serviceframework/ipc/objectendpoint_dbus.cpp728
-rw-r--r--src/serviceframework/ipc/objectendpoint_dbus_p.h103
-rw-r--r--src/serviceframework/ipc/objectendpoint_p.h92
-rw-r--r--src/serviceframework/ipc/proxyobject.cpp227
-rw-r--r--src/serviceframework/ipc/proxyobject_p.h80
-rw-r--r--src/serviceframework/ipc/qmetaobjectbuilder.cpp2611
-rw-r--r--src/serviceframework/ipc/qmetaobjectbuilder_p.h342
-rw-r--r--src/serviceframework/ipc/qremoteserviceregister_dbus_p.cpp359
-rw-r--r--src/serviceframework/ipc/qremoteserviceregister_dbus_p.h147
-rw-r--r--src/serviceframework/ipc/qremoteserviceregister_ls_p.cpp286
-rw-r--r--src/serviceframework/ipc/qremoteserviceregister_ls_p.h74
-rw-r--r--src/serviceframework/ipc/qremoteserviceregister_p.cpp100
-rw-r--r--src/serviceframework/ipc/qremoteserviceregister_p.h85
-rw-r--r--src/serviceframework/ipc/qremoteserviceregister_s60.cpp874
-rw-r--r--src/serviceframework/ipc/qremoteserviceregister_s60_p.h276
-rw-r--r--src/serviceframework/ipc/qremoteserviceregisterentry_p.h77
-rw-r--r--src/serviceframework/ipc/qservicemetaobject_dbus.cpp580
-rw-r--r--src/serviceframework/ipc/qservicemetaobject_dbus_p.h91
-rw-r--r--src/serviceframework/ipc/qservicepackage.cpp179
-rw-r--r--src/serviceframework/ipc/qservicepackage_p.h131
-rw-r--r--src/serviceframework/ipc/qsignalintercepter.cpp300
-rw-r--r--src/serviceframework/ipc/qsignalintercepter_p.h87
-rw-r--r--src/serviceframework/ipc/qslotinvoker.cpp269
-rw-r--r--src/serviceframework/ipc/qslotinvoker_p.h82
-rw-r--r--src/serviceframework/qabstractsecuritysession.cpp107
-rw-r--r--src/serviceframework/qabstractsecuritysession.h67
-rw-r--r--src/serviceframework/qremoteserviceregister.cpp461
-rw-r--r--src/serviceframework/qremoteserviceregister.h170
-rw-r--r--src/serviceframework/qservice.h76
-rw-r--r--src/serviceframework/qservice.qdoc74
-rw-r--r--src/serviceframework/qservicecontext.cpp210
-rw-r--r--src/serviceframework/qservicecontext.h93
-rw-r--r--src/serviceframework/qservicefilter.cpp540
-rw-r--r--src/serviceframework/qservicefilter.h122
-rw-r--r--src/serviceframework/qserviceframeworkglobal.h93
-rw-r--r--src/serviceframework/qserviceinterfacedescriptor.cpp418
-rw-r--r--src/serviceframework/qserviceinterfacedescriptor.h128
-rw-r--r--src/serviceframework/qserviceinterfacedescriptor_p.h126
-rw-r--r--src/serviceframework/qservicemanager.cpp796
-rw-r--r--src/serviceframework/qservicemanager.h158
-rw-r--r--src/serviceframework/qserviceplugininterface.cpp116
-rw-r--r--src/serviceframework/qserviceplugininterface.h76
-rw-r--r--src/serviceframework/servicedatabase.cpp2328
-rw-r--r--src/serviceframework/servicedatabase_p.h141
-rw-r--r--src/serviceframework/serviceframework.pro55
-rw-r--r--src/serviceframework/servicemetadata.cpp725
-rw-r--r--src/serviceframework/servicemetadata_p.h185
-rw-r--r--src/src.pro2
71 files changed, 20052 insertions, 1 deletions
diff --git a/src/serviceframework/databasemanager.cpp b/src/serviceframework/databasemanager.cpp
new file mode 100644
index 00000000..92ad8476
--- /dev/null
+++ b/src/serviceframework/databasemanager.cpp
@@ -0,0 +1,914 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "databasemanager_p.h"
+#include "qserviceinterfacedescriptor_p.h"
+#include <QFileSystemWatcher>
+#include <QHash>
+
+QTM_BEGIN_NAMESPACE
+
+DatabaseFileWatcher::DatabaseFileWatcher(DatabaseManager *parent)
+ : QObject(parent),
+ m_manager(parent),
+ m_watcher(0)
+{
+}
+
+QString DatabaseFileWatcher::closestExistingParent(const QString &path)
+{
+ if (QFile::exists(path))
+ return path;
+
+ int lastSep = path.lastIndexOf(QDir::separator());
+ if (lastSep < 0)
+ return QString();
+ return closestExistingParent(path.mid(0, lastSep));
+}
+
+void DatabaseFileWatcher::restartDirMonitoring(const QString &dbPath, const QString &previousDirPath)
+{
+ if (m_watcher->files().contains(dbPath))
+ return;
+
+ QString existing = closestExistingParent(dbPath);
+ if (existing.isEmpty()) {
+ qWarning() << "QServiceManager: can't find existing directory for path to database" << dbPath
+ << "serviceAdded() and serviceRemoved() will not be emitted";
+ return;
+ }
+ if (existing == dbPath) {
+ ServiceDatabase *db = 0;
+ DatabaseManager::DbScope scope;
+ if (m_manager->m_userDb && dbPath == m_manager->m_userDb->databasePath()) {
+ db = m_manager->m_userDb;
+ scope = DatabaseManager::UserOnlyScope;
+ } else if (dbPath == m_manager->m_systemDb->databasePath()) {
+ db = m_manager->m_systemDb;
+ scope = DatabaseManager::SystemScope;
+ }
+
+ if (db) {
+ if (!previousDirPath.isEmpty())
+ m_watcher->removePath(previousDirPath);
+ QMutableListIterator<QString> i(m_monitoredDbPaths);
+ while (i.hasNext()) {
+ if (i.next() == dbPath)
+ i.remove();
+ }
+
+ QStringList newServices = m_manager->getServiceNames(QString(), scope);
+ for (int i=0; i<newServices.count(); i++)
+ emit m_manager->serviceAdded(newServices[i], scope);
+ setEnabled(db, true);
+ }
+ } else {
+ if (previousDirPath != existing) {
+ if (!previousDirPath.isEmpty())
+ m_watcher->removePath(previousDirPath);
+ if (!m_watcher->directories().contains(existing))
+ m_watcher->addPath(existing);
+ if (!m_monitoredDbPaths.contains(dbPath))
+ m_monitoredDbPaths << dbPath;
+ }
+ }
+}
+
+void DatabaseFileWatcher::setEnabled(ServiceDatabase *database, bool enabled)
+{
+ if (!m_watcher) {
+ m_watcher = new QFileSystemWatcher(this);
+ connect(m_watcher, SIGNAL(fileChanged(QString)),
+ SLOT(databaseChanged(QString)));
+ connect(m_watcher, SIGNAL(directoryChanged(QString)),
+ SLOT(databaseDirectoryChanged(QString)));
+ }
+
+ QString path = database->databasePath();
+ if (enabled) {
+ if (QFile::exists(path)) {
+ m_knownServices[path] = database->getServiceNames(QString());
+ m_watcher->addPath(path);
+ } else {
+ restartDirMonitoring(path, QString());
+ }
+ } else {
+ m_watcher->removePath(path);
+ m_knownServices.remove(path);
+ }
+}
+
+void DatabaseFileWatcher::databaseDirectoryChanged(const QString &path)
+{
+ for (int i=0; i<m_monitoredDbPaths.count(); i++) {
+ if (m_monitoredDbPaths[i].contains(path))
+ restartDirMonitoring(m_monitoredDbPaths[i], path);
+ }
+}
+
+void DatabaseFileWatcher::databaseChanged(const QString &path)
+{
+ if (m_manager->m_userDb && path == m_manager->m_userDb->databasePath())
+ notifyChanges(m_manager->m_userDb, DatabaseManager::UserScope);
+ else if (path == m_manager->m_systemDb->databasePath())
+ notifyChanges(m_manager->m_systemDb, DatabaseManager::SystemScope);
+
+ // if database was deleted, the path may have been dropped
+ if (!m_watcher->files().contains(path) && QFile::exists(path))
+ m_watcher->addPath(path);
+}
+
+void DatabaseFileWatcher::notifyChanges(ServiceDatabase *database, DatabaseManager::DbScope scope)
+{
+ #ifdef Q_OS_SYMBIAN
+ scope = DatabaseManager::SystemScope;
+ #endif
+
+ QString dbPath = database->databasePath();
+ if (!QFile::exists(dbPath)) {
+ m_knownServices.remove(dbPath);
+ restartDirMonitoring(dbPath, QString());
+ return;
+ }
+
+ QStringList currentServices = database->getServiceNames(QString());
+ if (database->lastError().code() !=DBError::NoError) {
+ qWarning("QServiceManager: failed to get current service names for serviceAdded() and serviceRemoved() signals");
+ return;
+ }
+
+ const QStringList &knownServicesRef = m_knownServices[dbPath];
+
+ QSet<QString> currentServicesSet = currentServices.toSet();
+ QSet<QString> knownServicesSet = knownServicesRef.toSet();
+ if (currentServicesSet == knownServicesSet)
+ return;
+
+ QStringList newServices;
+ for (int i=0; i<currentServices.count(); i++) {
+ if (!knownServicesSet.contains(currentServices[i]))
+ newServices << currentServices[i];
+ }
+
+ QStringList removedServices;
+ for (int i=0; i<knownServicesRef.count(); i++) {
+ if (!currentServicesSet.contains(knownServicesRef[i]))
+ removedServices << knownServicesRef[i];
+ }
+
+ m_knownServices[dbPath] = currentServices;
+ for (int i=0; i<newServices.count(); i++)
+ emit m_manager->serviceAdded(newServices[i], scope);
+ for (int i=0; i<removedServices.count(); i++)
+ emit m_manager->serviceRemoved(removedServices[i], scope);
+}
+
+bool lessThan(const QServiceInterfaceDescriptor &d1,
+ const QServiceInterfaceDescriptor &d2)
+{
+ return (d1.majorVersion() < d2.majorVersion())
+ || ( d1.majorVersion() == d2.majorVersion()
+ && d1.minorVersion() < d2.minorVersion());
+}
+
+/*
+ \class DatabaseManager
+ The database manager is responsible for receiving queries about
+ services and managing user and system scope databases in order to
+ respond to those queries.
+
+ It provides operations for
+ - registering and unregistering services
+ - querying for services and interfaces
+ - setting and getting default interface implementations
+
+ and provides notifications by emitting signals for added
+ or removed services.
+
+ Implementation note:
+ When one of the above operations is first invoked a connection with the
+ appropriate database(s) is opened. This connection remains
+ open until the DatabaseManager is destroyed.
+
+ If the system scope database cannot be opened when performing
+ user scope operations. The operations are carried out as per normal
+ but only acting on the user scope database. Each operation invokation
+ will try to open a connection with the system scope database.
+
+ Terminology note:
+ When referring to user scope regarding operations, it generally
+ means access to both the user and system databases with the
+ data from both combined into a single dataset.
+ When referring to a user scope database it means the
+ user database only.
+
+ \since 1.0
+*/
+
+/*
+ Constructor
+*/
+DatabaseManager::DatabaseManager()
+ : m_userDb(NULL),
+ m_systemDb(new ServiceDatabase),
+ m_fileWatcher(0),
+ m_hasAccessedUserDb(false),
+ m_alreadyWarnedOpenError(false)
+{
+ #ifndef Q_OS_SYMBIAN
+ m_userDb = new ServiceDatabase;
+ initDbPath(UserScope);
+ #endif
+ initDbPath(SystemScope);
+}
+
+/*
+ Destructor
+*/
+DatabaseManager::~DatabaseManager()
+{
+ delete m_fileWatcher;
+ m_fileWatcher = 0;
+
+ //Aside: databases are implicitly closed
+ //during deletion
+ if (m_userDb) {
+ m_userDb->close();
+ delete m_userDb;
+ }
+ m_userDb = 0;
+
+ if (m_systemDb) {
+ m_systemDb->close();
+ delete m_systemDb;
+ }
+ m_systemDb = 0;
+}
+
+
+/*
+ Initialises database path of m_userDb
+ or m_systemDb, but does not open any
+ database connections
+*/
+void DatabaseManager::initDbPath(DbScope scope)
+{
+ #ifdef Q_OS_SYMBIAN
+ scope = SystemScope;
+ #endif
+
+ QSettings::Scope settingsScope;
+ QString dbIdentifier;
+ ServiceDatabase *db;
+ if (scope == SystemScope) {
+ settingsScope = QSettings::SystemScope;
+ dbIdentifier = QLatin1String("_system");
+ db = m_systemDb;
+ } else {
+ settingsScope = QSettings::UserScope;
+ dbIdentifier = QLatin1String("_user");
+ db = m_userDb;
+ }
+
+#ifdef QT_SIMULATOR
+ dbIdentifier.append(QLatin1String("_simulator"));
+#endif
+
+ #ifdef Q_OS_SYMBIAN
+ QDir dir(QDir::toNativeSeparators("C:\\Data\\temp\\QtServiceFW"));
+ #else
+ QSettings settings(QSettings::IniFormat, settingsScope,
+ QLatin1String("Nokia"), QLatin1String("QtServiceFramework"));
+ QFileInfo fi(settings.fileName());
+ QDir dir = fi.dir();
+ #endif
+ QString qtVersion = QLatin1String(qVersion());
+ qtVersion = qtVersion.left(qtVersion.size() -2); //strip off patch version
+ QString dbName = QString(QLatin1String("QtServiceFramework_")) + qtVersion + dbIdentifier + QLatin1String(".db");
+ db->setDatabasePath(dir.path() + QDir::separator() + dbName);
+}
+
+/*
+ Adds the details \a service into the service database corresponding to
+ \a scope.
+
+ Returns true if the operation succeeded and false otherwise.
+ The last error is set when this function is called.
+*/
+bool DatabaseManager::registerService(ServiceMetaDataResults &service, DbScope scope)
+{
+ #ifdef Q_OS_SYMBIAN
+ scope = SystemScope;
+ #endif
+
+ if (scope == DatabaseManager::SystemScope) {
+ if (!openDb(DatabaseManager::SystemScope)) {
+ return false;
+ } else {
+ if (!m_systemDb->registerService(service)) {
+ m_lastError = m_systemDb->lastError();
+ return false;
+ } else { //must be successful registration
+ m_lastError.setError(DBError::NoError);
+ return true;
+ }
+ }
+ } else { //must be registering service at user scope
+ if (!openDb(DatabaseManager::UserScope)) {
+ return false;
+ } else {
+ if (!m_userDb->registerService(service)) {
+ m_lastError = m_userDb->lastError();
+ return false;
+ } else { //must be successful registration
+ m_lastError.setError(DBError::NoError);
+ return true;
+ }
+ }
+ }
+}
+
+/*
+ Removes the details of \serviceName from the database corresponding to \a
+ scope.
+
+ Returns true if the operation succeeded, false otherwise.
+ The last error is set when this function is called.
+*/
+bool DatabaseManager::unregisterService(const QString &serviceName, DbScope scope)
+{
+ #ifdef Q_OS_SYMBIAN
+ scope = SystemScope;
+ #endif
+
+ if (scope == DatabaseManager::SystemScope) {
+ if (!openDb(DatabaseManager::SystemScope))
+ return false;
+ else {
+ if (!m_systemDb->unregisterService(serviceName)) {
+ m_lastError = m_systemDb->lastError();
+ return false;
+ } else { //must be successful unregistration
+ m_lastError.setError(DBError::NoError);
+ return true;
+ }
+ }
+ } else {
+ if (!openDb(DatabaseManager::UserScope)) {
+ return false;
+ } else {
+ if (!m_userDb->unregisterService(serviceName)){
+ m_lastError = m_userDb->lastError();
+ return false;
+ } else { //must be successful unregistration
+ m_lastError.setError(DBError::NoError);
+ return true;
+ }
+ }
+ }
+}
+
+/*
+ Removes the initialization specific information of \serviceName from the database
+ corresponding to a \scope.
+
+ Returns true if teh operation succeeded, false otherwise.
+ The last error is set when this function is called.
+ */
+bool DatabaseManager::serviceInitialized(const QString &serviceName, DbScope scope)
+{
+ ServiceDatabase *db = (scope == DatabaseManager::SystemScope) ? m_systemDb : m_userDb;
+
+ if (!openDb(scope)) {
+ return false;
+ } else {
+ if (!db->serviceInitialized(serviceName)) {
+ m_lastError = db->lastError();
+ return false;
+ } else {
+ m_lastError.setError(DBError::NoError);
+ return true;
+ }
+ }
+}
+
+/*
+ Retrieves a list of interface descriptors that fulfill the constraints specified
+ by \a filter at a given \a scope.
+
+ The last error is set when this function is called.
+*/
+QList<QServiceInterfaceDescriptor> DatabaseManager::getInterfaces(const QServiceFilter &filter, DbScope scope)
+{
+ #ifdef Q_OS_SYMBIAN
+ QService::Scope requestedScope;
+ if (scope == UserScope) {
+ requestedScope = QService::UserScope;
+ } else {
+ requestedScope = QService::SystemScope;
+ }
+ scope = SystemScope;
+ #endif
+
+ QList<QServiceInterfaceDescriptor> descriptors;
+
+ int userDescriptorCount = 0;
+ if (scope == UserScope) {
+ if (!openDb(UserScope))
+ return descriptors;
+
+ descriptors = m_userDb->getInterfaces(filter);
+ if (m_userDb->lastError().code() != DBError::NoError ) {
+ descriptors.clear();
+ m_lastError = m_userDb->lastError();
+ return descriptors;
+ }
+
+ userDescriptorCount = descriptors.count();
+ for (int i=0; i < userDescriptorCount; ++i) {
+ descriptors[i].d->scope = QService::UserScope;
+ }
+ }
+
+ if (openDb(SystemScope)) {
+ descriptors.append(m_systemDb->getInterfaces(filter));
+ if (m_systemDb->lastError().code() != DBError::NoError) {
+ descriptors.clear();
+ m_lastError = m_systemDb->lastError();
+ return descriptors;
+ }
+
+ for (int i = userDescriptorCount; i < descriptors.count(); ++i) {
+ #ifdef Q_OS_SYMBIAN
+ descriptors[i].d->scope = requestedScope;
+ #else
+ descriptors[i].d->scope = QService::SystemScope;
+ #endif
+ }
+ } else {
+ if ( scope == SystemScope) {
+ //openDb() should already have handled lastError
+ descriptors.clear();
+ return descriptors;
+ }
+ }
+
+ m_lastError.setError(DBError::NoError);
+ return descriptors;
+}
+
+
+/*
+ Retrieves a list of the names of services that provide the interface
+ specified by \a interfaceName.
+
+ The last error is set when this function is called.
+*/
+QStringList DatabaseManager::getServiceNames(const QString &interfaceName, DatabaseManager::DbScope scope)
+{
+ #ifdef Q_OS_SYMBIAN
+ scope = SystemScope;
+ #endif
+
+ QStringList serviceNames;
+ if (scope == UserScope || scope == UserOnlyScope) {
+ if (!openDb(DatabaseManager::UserScope))
+ return serviceNames;
+ serviceNames = m_userDb->getServiceNames(interfaceName);
+ if (m_userDb->lastError().code() != DBError::NoError) {
+ serviceNames.clear();
+ m_lastError = m_userDb->lastError();
+ return serviceNames;
+ }
+ if (scope == UserOnlyScope) {
+ m_lastError.setError(DBError::NoError);
+ return serviceNames;
+ }
+ }
+
+ if (openDb(DatabaseManager::SystemScope)) {
+ QStringList systemServiceNames;
+ systemServiceNames = m_systemDb->getServiceNames(interfaceName);
+ if (m_systemDb->lastError().code() != DBError::NoError) {
+ serviceNames.clear();
+ m_lastError = m_systemDb->lastError();
+ return serviceNames;
+ }
+ foreach (const QString &systemServiceName, systemServiceNames) {
+ if (!serviceNames.contains(systemServiceName, Qt::CaseInsensitive))
+ serviceNames.append(systemServiceName);
+ }
+
+ } else {
+ if ( scope == SystemScope) {
+ //openDb() should have already handled lastError
+ serviceNames.clear();
+ return serviceNames;
+ }
+ }
+
+ m_lastError.setError(DBError::NoError);
+ return serviceNames;
+}
+
+/*
+ Returns the default interface implementation descriptor for a given
+ \a interfaceName and \a scope.
+
+ The last error is set when this function is called.
+*/
+QServiceInterfaceDescriptor DatabaseManager::interfaceDefault(const QString &interfaceName, DbScope scope)
+{
+ #ifdef Q_OS_SYMBIAN
+ QService::Scope requestedScope;
+ if (scope == UserScope) {
+ requestedScope = QService::UserScope;
+ } else {
+ requestedScope = QService::SystemScope;
+ }
+ scope = SystemScope;
+ #endif
+
+ QServiceInterfaceDescriptor descriptor;
+ if (scope == UserScope) {
+ if (!openDb(UserScope))
+ return QServiceInterfaceDescriptor();
+ QString interfaceID;
+ descriptor = m_userDb->interfaceDefault(interfaceName, &interfaceID);
+
+ if (m_userDb->lastError().code() == DBError::NoError) {
+ descriptor.d->scope = QService::UserScope;
+ return descriptor;
+ } else if (m_userDb->lastError().code() == DBError::ExternalIfaceIDFound) {
+ //default hasn't been found in user db, but we have found an ID
+ //that may refer to an interface implementation in the system db
+ if (!openDb(SystemScope)) {
+ QString errorText(QLatin1String("No default service found for interface: \"%1\""));
+ m_lastError.setError(DBError::NotFound, errorText.arg(interfaceName));
+ return QServiceInterfaceDescriptor();
+ }
+
+ descriptor = m_systemDb->getInterface(interfaceID);
+ //found the service from the system database
+ if (m_systemDb->lastError().code() == DBError::NoError) {
+ m_lastError.setError(DBError::NoError);
+ descriptor.d->scope = QService::SystemScope;
+ return descriptor;
+ } else if (m_systemDb->lastError().code() == DBError::NotFound) {
+ //service implementing interface doesn't exist in the system db
+ //so the user db must contain a stale entry so remove it
+ m_userDb->removeExternalDefaultServiceInterface(interfaceID);
+
+ QList<QServiceInterfaceDescriptor> descriptors;
+ descriptors = getInterfaces(QServiceFilter(interfaceName), UserScope);
+
+ //make the latest interface implementation the new
+ //default if there is one
+ if (descriptors.count() > 0 ) {
+ descriptor = latestDescriptor(descriptors);
+ setInterfaceDefault(descriptor, UserScope);
+ m_lastError.setError(DBError::NoError);
+ return descriptor;
+ } else {
+ QString errorText(QLatin1String("No default service found for interface: \"%1\""));
+ m_lastError.setError(DBError::NotFound, errorText.arg(interfaceName));
+ return QServiceInterfaceDescriptor();
+ }
+ } else {
+ m_lastError.setError(DBError::NoError);
+ return QServiceInterfaceDescriptor();
+ }
+ } else if (m_userDb->lastError().code() == DBError::NotFound) {
+ //do nothing, the search for a default in the system db continues
+ //further down
+ } else { //error occurred at user db level, so return
+ m_lastError = m_userDb->lastError();
+ return QServiceInterfaceDescriptor();
+ }
+ }
+
+ //search at system scope because we haven't found a default at user scope
+ //or because we're specifically only querying at system scope
+ if (!openDb(SystemScope)) {
+ if (scope == SystemScope) {
+ m_lastError = m_systemDb->lastError();
+ return QServiceInterfaceDescriptor();
+ } else if (scope == UserScope && m_userDb && m_userDb->lastError().code() == DBError::NotFound) {
+ m_lastError = m_userDb->lastError();
+ return QServiceInterfaceDescriptor();
+ }
+ } else {
+ descriptor = m_systemDb->interfaceDefault(interfaceName);
+ if (m_systemDb->lastError().code() == DBError::NoError) {
+ #ifdef Q_OS_SYMBIAN
+ descriptor.d->scope = requestedScope;
+ #else
+ descriptor.d->scope = QService::SystemScope;
+ #endif
+ return descriptor;
+ } else if (m_systemDb->lastError().code() == DBError::NotFound) {
+ m_lastError = m_systemDb->lastError();
+ return QServiceInterfaceDescriptor();
+ } else {
+ m_lastError = m_systemDb->lastError();
+ return QServiceInterfaceDescriptor();
+ }
+ }
+
+ //should not be possible to reach here
+ m_lastError.setError(DBError::UnknownError);
+ return QServiceInterfaceDescriptor();
+}
+
+/*
+ Sets the default interface implemenation for \a interfaceName to the matching
+ interface implementation provided by \a service.
+
+ If \a service provides more than one interface implementation, the newest
+ version of the interface is set as the default.
+
+ Returns true if the operation was succeeded, false otherwise
+ The last error is set when this function is called.
+*/
+bool DatabaseManager::setInterfaceDefault(const QString &serviceName, const
+ QString &interfaceName, DbScope scope)
+{
+ QList<QServiceInterfaceDescriptor> descriptors;
+ QServiceFilter filter;
+ filter.setServiceName(serviceName);
+ filter.setInterface(interfaceName);
+
+ descriptors = getInterfaces(filter, scope);
+ if (m_lastError.code() != DBError::NoError)
+ return false;
+
+ if (descriptors.count() == 0) {
+ QString errorText(QLatin1String("No implementation for interface \"%1\" "
+ "found for service \"%2\""));
+ m_lastError.setError(DBError::NotFound,
+ errorText.arg(interfaceName)
+ .arg(serviceName));
+ return false;
+ }
+
+ //find the descriptor with the latest version
+ int latestIndex = 0;
+ for (int i = 1; i < descriptors.count(); ++i) {
+ if (lessThan(descriptors[latestIndex], descriptors[i]))
+ latestIndex = i;
+ }
+
+ return setInterfaceDefault(descriptors[latestIndex], scope);
+}
+
+/*
+ Sets the interface implementation specified by \a descriptor to be the default
+ implementation for the particular interface specified in the descriptor.
+
+ Returns true if the operation succeeded, false otherwise.
+ The last error is set when this function is called.
+*/
+bool DatabaseManager::setInterfaceDefault(const QServiceInterfaceDescriptor &descriptor, DbScope scope)
+{
+ #ifdef Q_OS_SYMBIAN
+ Q_UNUSED(scope);
+ if (!openDb(SystemScope)) {
+ return false;
+ } else {
+ if (m_systemDb->setInterfaceDefault(descriptor)) {
+ m_lastError.setError(DBError::NoError);
+ return true;
+ } else {
+ m_lastError = m_systemDb->lastError();
+ return false;
+ }
+ }
+ #else
+ if (scope == UserScope) {
+ if (!openDb(UserScope))
+ return false;
+ if (descriptor.scope() == QService::UserScope) { //if a user scope descriptor, just set it in the user db
+ if (m_userDb->setInterfaceDefault(descriptor)) {
+ m_lastError.setError(DBError::NoError);
+ return true;
+ } else {
+ m_lastError = m_userDb->lastError();
+ return false;
+ }
+ } else { //otherwise we need to get the interfaceID from the system db and set this
+ //as an external default interface ID in the user db
+ if (!openDb(SystemScope))
+ return false;
+
+ QString interfaceDescriptorID = m_systemDb->getInterfaceID(descriptor);
+ if (m_systemDb->lastError().code() == DBError::NoError) {
+ if (m_userDb->setInterfaceDefault(descriptor, interfaceDescriptorID)) {
+ m_lastError.setError(DBError::NoError);
+ return true;
+ } else {
+ m_lastError = m_userDb->lastError();
+ return false;
+ }
+ } else {
+ m_lastError = m_systemDb->lastError();
+ return false;
+ }
+ }
+ } else { //scope == SystemScope
+ if (descriptor.scope() == QService::UserScope) {
+ QString errorText(QLatin1String("Cannot set default service at system scope with a user scope "
+ "interface descriptor"));
+ m_lastError.setError(DBError::InvalidDescriptorScope, errorText);
+ return false;
+ } else {
+ if (!openDb(SystemScope)) {
+ return false;
+ } else {
+ if (m_systemDb->setInterfaceDefault(descriptor)) {
+ m_lastError.setError(DBError::NoError);
+ return true;
+ } else {
+ m_lastError = m_systemDb->lastError();
+ return false;
+ }
+ }
+ }
+ }
+ #endif
+}
+
+/*
+ Opens a database connection with the database at a specific \a scope.
+
+ The last error is set when this function is called.
+*/
+bool DatabaseManager::openDb(DbScope scope)
+{
+ #ifdef Q_OS_SYMBIAN
+ scope = SystemScope;
+ #endif
+
+ if (scope == SystemScope && m_systemDb->isOpen() && !QFile::exists(m_systemDb->databasePath())) {
+ delete m_systemDb;
+ m_systemDb = new ServiceDatabase;
+ initDbPath(SystemScope);
+ m_alreadyWarnedOpenError = false;
+ } else if (scope != SystemScope && m_userDb->isOpen() && !QFile::exists(m_userDb->databasePath())) {
+ delete m_userDb;
+ m_userDb = new ServiceDatabase;
+ initDbPath(UserScope);
+ m_alreadyWarnedOpenError = false;
+ }
+
+ ServiceDatabase *db;
+ if (scope == SystemScope) {
+ db = m_systemDb;
+ }
+ else {
+ db = m_userDb;
+ m_hasAccessedUserDb = true;
+ }
+
+ if (db->isOpen())
+ return true;
+
+ bool isOpen = db->open();
+ if (!isOpen) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "DatabaseManger::openDb():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ if (scope == SystemScope && m_hasAccessedUserDb == true) {
+ if (QFile::exists(m_systemDb->databasePath()) && !m_alreadyWarnedOpenError)
+ qWarning() << "Service Framework:- Unable to access system database for a user scope "
+ "operation; resorting to using only the user database. Future operations "
+ "will attempt to access the system database but no further warnings will be issued";
+ }
+
+ QString warning;
+ if (db->lastError().code() == DBError::InvalidDatabaseFile) {
+ warning = QString(QLatin1String("Service Framework:- Database file is corrupt or invalid: ")) + db->databasePath();
+ m_lastError = db->lastError();
+ } else {
+ warning = QString(QLatin1String("Service Framework:- Unable to open or create database at: ")) + db->databasePath();
+ QString errorText(QLatin1String("Unable to open service framework database: %1"));
+ m_lastError.setError(DBError::CannotOpenServiceDb,
+ errorText.arg(db->databasePath()));
+ }
+
+ if (m_alreadyWarnedOpenError
+ || (scope == SystemScope && m_hasAccessedUserDb && !QFile::exists(m_systemDb->databasePath()))) {
+ //do nothing, don't output warning if already warned or we're accessing the system database
+ //from user scope and the system database doesn't exist
+ } else {
+ qWarning() << qPrintable(warning);
+ m_alreadyWarnedOpenError = true;
+ }
+
+ return false;
+ }
+
+ //if we are opening the system database while the user database is open,
+ //cleanup and reset any old external defaults
+ //from the user scope database
+ if (scope == SystemScope && m_userDb && m_userDb->isOpen()) {
+ QList<QPair<QString,QString> > externalDefaultsInfo;
+ externalDefaultsInfo = m_userDb->externalDefaultsInfo();
+ QServiceInterfaceDescriptor descriptor;
+ QPair<QString,QString> defaultInfo;
+
+ for (int i = 0; i < externalDefaultsInfo.count(); ++i) {
+ defaultInfo = externalDefaultsInfo[i];
+ descriptor = m_userDb->getInterface(defaultInfo.second);
+ if (m_userDb->lastError().code() == DBError::NotFound) {
+ m_userDb->removeExternalDefaultServiceInterface(defaultInfo.second);
+ QList<QServiceInterfaceDescriptor> descriptors;
+ descriptors = getInterfaces(QServiceFilter(defaultInfo.first), UserScope);
+
+ if (descriptors.count() > 0 ) {
+ descriptor = latestDescriptor(descriptors);
+ setInterfaceDefault(descriptor, UserScope);
+ }
+ }
+ }
+ }
+
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+/*
+ Returns the interface descriptor with the highest version from the
+ list of interface \a descriptors
+*/
+QServiceInterfaceDescriptor DatabaseManager::latestDescriptor(
+ const QList<QServiceInterfaceDescriptor> &descriptors)
+{
+ if (descriptors.count() == 0)
+ return QServiceInterfaceDescriptor();
+
+ int latestIndex = 0;
+ for (int i = 1; i < descriptors.count(); ++i) {
+ if (lessThan(descriptors[latestIndex], descriptors[i]))
+ latestIndex = i;
+ }
+
+ return descriptors[latestIndex];
+}
+
+/*
+ Sets whether change notifications for added and removed services are
+ \a enabled or not at a given \a scope.
+*/
+void DatabaseManager::setChangeNotificationsEnabled(DbScope scope, bool enabled)
+{
+ #ifdef Q_OS_SYMBIAN
+ scope = SystemScope;
+ #endif
+
+ if (!m_fileWatcher) m_fileWatcher = new
+ DatabaseFileWatcher(this); m_fileWatcher->setEnabled(scope == SystemScope ?
+ m_systemDb : m_userDb, enabled);
+}
+
+#include "moc_databasemanager_p.cpp"
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/databasemanager_p.h b/src/serviceframework/databasemanager_p.h
new file mode 100644
index 00000000..b5ff070f
--- /dev/null
+++ b/src/serviceframework/databasemanager_p.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DATABASEMANAGER_H_
+#define DATABASEMANAGER_H_
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qserviceframeworkglobal.h"
+#include "servicedatabase_p.h"
+#include <QObject>
+
+#ifdef QT_SFW_SERVICEDATABASE_GENERATE
+#undef Q_AUTOTEST_EXPORT
+#define Q_AUTOTEST_EXPORT
+#endif
+
+QT_BEGIN_HEADER
+QTM_BEGIN_NAMESPACE
+
+class DatabaseFileWatcher;
+class Q_AUTOTEST_EXPORT DatabaseManager : public QObject
+{
+ Q_OBJECT
+
+ public:
+ enum DbScope{UserScope, SystemScope, UserOnlyScope};
+ DatabaseManager(void);
+ virtual ~DatabaseManager();
+
+ bool registerService(ServiceMetaDataResults &service, DbScope scope);
+ bool unregisterService(const QString &serviceName, DbScope scope);
+ bool serviceInitialized(const QString &serviceName, DbScope scope);
+
+ QList<QServiceInterfaceDescriptor> getInterfaces(const QServiceFilter &filter, DbScope scope);
+ QStringList getServiceNames(const QString &interfaceName, DbScope scope);
+
+ QServiceInterfaceDescriptor interfaceDefault(const QString &interfaceName, DbScope scope);
+ bool setInterfaceDefault(const QString &serviceName, const QString &interfaceName, DbScope scope);
+ bool setInterfaceDefault(const QServiceInterfaceDescriptor &interface, DbScope scope);
+
+ DBError lastError(){ return m_lastError;}
+
+ void setChangeNotificationsEnabled(DbScope scope, bool enabled);
+
+ signals:
+ void serviceAdded(const QString &serviceName, DatabaseManager::DbScope scope);
+ void serviceRemoved(const QString &serviceName, DatabaseManager::DbScope scope);
+
+ private:
+ void initDbPath(DbScope scope);
+ bool openDb(DbScope scope);
+
+ ServiceDatabase *m_userDb;
+ ServiceDatabase *m_systemDb;
+ DBError m_lastError;
+
+ friend class DatabaseFileWatcher;
+ DatabaseFileWatcher *m_fileWatcher;
+ QServiceInterfaceDescriptor latestDescriptor(const QList<QServiceInterfaceDescriptor> &descriptors);
+
+ bool m_hasAccessedUserDb;
+ bool m_alreadyWarnedOpenError;
+};
+
+
+class Q_AUTOTEST_EXPORT DatabaseFileWatcher : public QObject
+{
+ Q_OBJECT
+public:
+ DatabaseFileWatcher(DatabaseManager *parent = 0);
+
+ void setEnabled(ServiceDatabase *database, bool enabled);
+
+private slots:
+ void databaseChanged(const QString &path);
+ void databaseDirectoryChanged(const QString &path);
+
+private:
+ void notifyChanges(ServiceDatabase *database, DatabaseManager::DbScope scope);
+ QString closestExistingParent(const QString &path);
+ void restartDirMonitoring(const QString &dbPath, const QString &previousDirPath);
+
+ DatabaseManager *m_manager;
+ QFileSystemWatcher *m_watcher;
+ QHash<QString, QStringList> m_knownServices;
+ QStringList m_monitoredDbPaths;
+};
+
+QTM_END_NAMESPACE
+QT_END_HEADER
+
+#endif
diff --git a/src/serviceframework/databasemanager_symbian.cpp b/src/serviceframework/databasemanager_symbian.cpp
new file mode 100644
index 00000000..575f4f88
--- /dev/null
+++ b/src/serviceframework/databasemanager_symbian.cpp
@@ -0,0 +1,541 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#if defined(__WINS__) && !defined(SYMBIAN_EMULATOR_SUPPORTS_PERPROCESS_WSD)
+//Use DatabaseManager "directly" in emulators where per process WSD is not
+//supported.
+#include "databasemanager.cpp"
+#include "servicedatabase.cpp"
+#else //defined(__WINS__) && !defined(SYMBIAN_EMULATOR_SUPPORTS_PERPROCESS_WSD)
+
+#ifdef QTM_BUILD_UNITTESTS
+#include "servicedatabase.cpp"
+#endif
+
+#include "databasemanager_symbian_p.h"
+#include "clientservercommon.h"
+#include <qserviceinterfacedescriptor_p.h>
+#include <qserviceinterfacedescriptor.h>
+#include <qservicefilter.h>
+#include <QProcess>
+#include <QDebug>
+#include <s32mem.h>
+
+QTM_BEGIN_NAMESPACE
+
+/*
+ \class DatabaseManager
+ \ingroup servicesfw
+ \brief The database manager is responsible for receiving queries
+ about services and managing user and system scope databases in order to
+ respond to those queries.
+
+ The DatabaseManager provides operations for
+ - registering and unregistering services
+ - querying for services and interfaces
+ - setting and getting default interface implementations
+
+ and provides notifications by emitting signals for added
+ or removed services.
+
+ Implementation note:
+ When one of the above operations is first invoked a connection with the
+ appropriate database(s) is opened. This connection remains
+ open until the DatabaseManager is destroyed.
+
+ If the system scope database cannot be opened when performing
+ user scope operations. The operations are carried out as per normal
+ but only acting on the user scope database. Each operation invokation
+ will try to open a connection with the system scope database.
+
+ Terminology note:
+ When referring to user scope regarding operations, it generally
+ means access to both the user and system databases with the
+ data from both combined into a single dataset.
+ When referring to a user scope database it means the
+ user database only.
+*/
+
+/*
+ \fn DatabaseManager::DatabaseManager()
+
+ Constructor
+*/
+DatabaseManager::DatabaseManager()
+{
+ TInt err = iSession.Connect();
+ if (err != KErrNone)
+ qt_symbian_throwIfError(err);
+
+ iDatabaseManagerSignalMonitor = new DatabaseManagerSignalMonitor(*this, iSession);
+}
+
+/*
+ \fn DatabaseManager::~DatabaseManager()
+
+ Destructor
+*/
+DatabaseManager::~DatabaseManager()
+{
+ delete iDatabaseManagerSignalMonitor;
+ iSession.Close();
+}
+
+/*
+ \fn bool DatabaseManager::registerService(ServiceMetaDataResults &service, DbScope scope)
+
+ Adds the details \a service into the service database corresponding to
+ \a scope.
+
+ Returns true if the operation succeeded and false otherwise.
+ The last error is set when this function is called.
+*/
+bool DatabaseManager::registerService(ServiceMetaDataResults &service, DbScope scope)
+{
+ Q_UNUSED(scope);
+ return iSession.RegisterService(service);
+}
+
+/*
+ \fn bool DatabaseManager::unregisterService(const QString &serviceName, DbScope scope)
+
+ Removes the details of \a serviceName from the database corresponding to \a
+ scope.
+
+ Returns true if the operation succeeded, false otherwise.
+ The last error is set when this function is called.
+*/
+bool DatabaseManager::unregisterService(const QString &serviceName, DbScope scope)
+{
+ Q_UNUSED(scope);
+ return iSession.UnregisterService(serviceName);
+}
+
+/*
+ Removes the initialization specific information of \serviceName from the database.
+
+ Returns true if the operation succeeded, false otherwise.
+ The last error is set when this function is called.
+ */
+bool DatabaseManager::serviceInitialized(const QString &serviceName, DbScope scope)
+{
+ Q_UNUSED(scope);
+ return iSession.ServiceInitialized(serviceName);
+}
+
+/*
+ \fn QList<QServiceInterfaceDescriptor> DatabaseManager::getInterfaces(const QServiceFilter &filter, DbScope scope)
+
+ Retrieves a list of interface descriptors that fulfill the constraints specified
+ by \a filter at a given \a scope.
+
+ The last error is set when this function is called.
+*/
+QList<QServiceInterfaceDescriptor> DatabaseManager::getInterfaces(const QServiceFilter &filter, DbScope scope)
+{
+ Q_UNUSED(scope);
+ return iSession.Interfaces(filter);
+}
+
+
+/*
+ \fn QStringList DatabaseManager::getServiceNames(const QString &interfaceName, DbScope scope)
+
+ Retrieves a list of the names of services that provide the interface
+ specified by \a interfaceName.
+
+ The last error is set when this function is called.
+*/
+QStringList DatabaseManager::getServiceNames(const QString &interfaceName, DbScope scope)
+{
+ Q_UNUSED(scope);
+ return iSession.ServiceNames(interfaceName);
+}
+
+/*
+ \fn QServiceInterfaceDescriptor DatabaseManager::interfaceDefault(const QString &interfaceName, DbScope scope)
+
+ Returns the default interface implementation descriptor for a given
+ \a interfaceName and \a scope.
+
+ The last error is set when this function is called.
+*/
+QServiceInterfaceDescriptor DatabaseManager::interfaceDefault(const QString &interfaceName, DbScope scope)
+{
+ Q_UNUSED(scope);
+ return iSession.InterfaceDefault(interfaceName);
+}
+
+/*
+ \fn bool DatabaseManager::setInterfaceDefault(const QString &serviceName, const QString &interfaceName, DbScope scope)
+
+ Sets the default interface implemenation for \a interfaceName to the matching
+ interface implementation provided by \a service.
+
+ If \a service provides more than one interface implementation, the newest
+ version of the interface is set as the default.
+
+ Returns true if the operation was succeeded, false otherwise
+ The last error is set when this function is called.
+*/
+bool DatabaseManager::setInterfaceDefault(const QString &serviceName, const
+ QString &interfaceName, DbScope scope) {
+ Q_UNUSED(scope);
+ return iSession.SetInterfaceDefault(serviceName, interfaceName);
+}
+
+/*
+ \fn bool DatabaseManager::setInterfaceDefault(const QServiceInterfaceDescriptor &descriptor, DbScope scope)
+
+ Sets the interface implementation specified by \a descriptor to be the default
+ implementation for the particular interface specified in the descriptor.
+
+ Returns true if the operation succeeded, false otherwise.
+ The last error is set when this function is called.
+*/
+bool DatabaseManager::setInterfaceDefault(const QServiceInterfaceDescriptor &descriptor, DbScope scope)
+{
+ Q_UNUSED(scope);
+ return iSession.SetInterfaceDefault(descriptor);
+}
+
+/*
+ \fn void DatabaseManager::setChangeNotificationsEnabled(DbScope scope, bool enabled)
+
+ Sets whether change notifications for added and removed services are
+ \a enabled or not at a given \a scope.
+*/
+void DatabaseManager::setChangeNotificationsEnabled(DbScope scope, bool enabled)
+{
+ Q_UNUSED(scope);
+ iSession.SetChangeNotificationsEnabled(enabled);
+}
+
+DatabaseManagerSignalMonitor::DatabaseManagerSignalMonitor(
+ DatabaseManager& databaseManager, RDatabaseManagerSession& databaseManagerSession) :
+ CActive(EPriorityNormal),
+ iDatabaseManager(databaseManager), iDatabaseManagerSession(databaseManagerSession)
+{
+ CActiveScheduler::Add(this);
+ issueNotifyServiceSignal();
+}
+
+DatabaseManagerSignalMonitor::~DatabaseManagerSignalMonitor()
+{
+ Cancel();
+}
+
+void DatabaseManagerSignalMonitor::issueNotifyServiceSignal()
+{
+ iDatabaseManagerSession.NotifyServiceSignal(iStatus);
+ SetActive();
+}
+
+DBError DatabaseManager::lastError()
+{
+ return iSession.LastError();
+}
+
+void DatabaseManagerSignalMonitor::DoCancel()
+{
+ iDatabaseManagerSession.CancelNotifyServiceSignal();
+}
+
+void DatabaseManagerSignalMonitor::RunL()
+{
+ switch (iStatus.Int())
+ {
+ case ENotifySignalComplete:
+ {
+ QString serviceName = QString::fromUtf16(iDatabaseManagerSession.iServiceName.Ptr(), iDatabaseManagerSession.iServiceName.Length());
+
+ if ((DatabaseManager::State)iDatabaseManagerSession.iState() == DatabaseManager::EAdded)
+ {
+ emit iDatabaseManager.serviceAdded(serviceName, DatabaseManager::SystemScope);
+ }
+ else if ((DatabaseManager::State)iDatabaseManagerSession.iState() == DatabaseManager::ERemoved)
+ {
+ emit iDatabaseManager.serviceRemoved(serviceName, DatabaseManager::SystemScope);
+ }
+ issueNotifyServiceSignal();
+ break;
+ }
+ default:
+ {
+
+ }
+ break;
+ }
+}
+
+
+RDatabaseManagerSession::RDatabaseManagerSession()
+ : RSessionBase()
+ {
+ }
+
+TVersion RDatabaseManagerSession::Version() const
+ {
+ return TVersion(KServerMajorVersionNumber, KServerMinorVersionNumber, KServerBuildVersionNumber);
+ }
+
+TInt RDatabaseManagerSession::Connect()
+ {
+ TInt retryCount = 2;
+ for (;;)
+ {
+ TInt err = CreateSession(KDatabaseManagerServerName, TVersion(), 8, EIpcSession_Sharable);
+ if (err != KErrNotFound && err != KErrServerTerminated)
+ return err;
+ if (--retryCount == 0)
+ return err;
+ err = StartServer();
+ if (err != KErrNone && err != KErrAlreadyExists)
+ return err;
+ }
+ }
+
+TInt RDatabaseManagerSession::StartServer()
+ {
+ TInt ret = KErrNone;
+ TFindServer findServer(KDatabaseManagerServerName);
+ TFullName name;
+
+ if (findServer.Next(name) != KErrNone)
+ {
+ TRequestStatus status;
+ RProcess dbServer;
+ ret = dbServer.Create(KDatabaseManagerServerProcess, KNullDesC);
+ if(ret != KErrNone)
+ {
+ return ret;
+ }
+ dbServer.Rendezvous(status);
+ if(status != KRequestPending)
+ {
+ dbServer.Kill(KErrNone);
+ dbServer.Close();
+ return KErrGeneral;
+ }
+ else
+ {
+ dbServer.Resume();
+ }
+
+ User::WaitForRequest(status);
+ if(status != KErrNone)
+ {
+ dbServer.Close();
+ return status.Int();
+ }
+ dbServer.Close();
+ }
+
+ return ret;
+ }
+
+void RDatabaseManagerSession::Close()
+ {
+ RSessionBase::Close();
+ }
+
+bool RDatabaseManagerSession::RegisterService(ServiceMetaDataResults& aService)
+ {
+ QByteArray serviceByteArray;
+ QDataStream in(&serviceByteArray, QIODevice::WriteOnly);
+ in.setVersion(QDataStream::Qt_4_6);
+ in << aService;
+ TPtrC8 ptr8((TUint8*)(serviceByteArray.constData()), serviceByteArray.size());
+ TIpcArgs args(&ptr8, &iError);
+ SendReceive(ERegisterServiceRequest, args);
+
+ return (iError() == DBError::NoError);
+ }
+
+bool RDatabaseManagerSession::UnregisterService(const QString& aServiceName)
+ {
+ TPtrC serviceNamePtr(reinterpret_cast<const TUint16*>(aServiceName.utf16()));
+ TIpcArgs args(&serviceNamePtr, &iError);
+ SendReceive(EUnregisterServiceRequest, args);
+
+ return (iError() == DBError::NoError);
+ }
+
+bool RDatabaseManagerSession::ServiceInitialized(const QString& aServiceName)
+ {
+ TPtrC serviceNamePtr(reinterpret_cast<const TUint16*>(aServiceName.utf16()));
+ TIpcArgs args(&serviceNamePtr, &iError);
+ SendReceive(EServiceInitializedRequest, args);
+
+ return (iError() == DBError::NoError);
+ }
+
+
+QList<QServiceInterfaceDescriptor> RDatabaseManagerSession::Interfaces(const QServiceFilter& aFilter)
+ {
+ QByteArray filterByteArray;
+ QDataStream in(&filterByteArray, QIODevice::WriteOnly);
+ in.setVersion(QDataStream::Qt_4_6);
+ in << aFilter;
+ TPtrC8 ptr8((TUint8*)(filterByteArray.constData()), filterByteArray.size());
+ TPckgBuf<TInt> lengthPckg(0);
+ TIpcArgs args(&ptr8, &lengthPckg, &iError);
+ SendReceive(EGetInterfacesSizeRequest, args);
+
+ HBufC8* descriptorListBuf = HBufC8::New(lengthPckg());
+ TPtr8 ptrToBuf(descriptorListBuf->Des());
+ TIpcArgs args2(&ptrToBuf);
+ SendReceive(EGetInterfacesRequest, args2);
+
+ QByteArray descriptorListByteArray((const char*)ptrToBuf.Ptr(), ptrToBuf.Length());
+ QDataStream out(descriptorListByteArray);
+ QList<QServiceInterfaceDescriptor> descriptorList;
+ out >> descriptorList;
+
+ delete descriptorListBuf;
+
+ return descriptorList;
+ }
+
+QStringList RDatabaseManagerSession::ServiceNames(const QString& aInterfaceName)
+ {
+ TPtrC interfaceNamePtr(reinterpret_cast<const TUint16*>(aInterfaceName.utf16()));
+ HBufC* interfaceNamebuf = HBufC::New(interfaceNamePtr.Length());
+ interfaceNamebuf->Des().Copy(interfaceNamePtr);
+ TPckgBuf<TInt> lengthPckg(0);
+ TIpcArgs args(interfaceNamebuf, &lengthPckg, &iError);
+ SendReceive(EGetServiceNamesSizeRequest, args);
+
+ HBufC8* serviceNamesBuf = HBufC8::New(lengthPckg());
+ TPtr8 ptrToBuf(serviceNamesBuf->Des());
+ TIpcArgs args2(&ptrToBuf);
+ SendReceive(EGetServiceNamesRequest, args2);
+
+ QByteArray nameListByteArray((const char*)ptrToBuf.Ptr(), ptrToBuf.Length());
+ QDataStream out(nameListByteArray);
+ QStringList nameList;
+ out >> nameList;
+
+ delete interfaceNamebuf;
+ delete serviceNamesBuf;
+
+ return nameList;
+ }
+
+QServiceInterfaceDescriptor RDatabaseManagerSession::InterfaceDefault(const QString& aInterfaceName)
+ {
+ TPtrC interfaceNamePtr(reinterpret_cast<const TUint16*>(aInterfaceName.utf16()));
+ HBufC* interfaceNameBuf = HBufC::New(interfaceNamePtr.Length());
+ interfaceNameBuf->Des().Copy(interfaceNamePtr);
+ TPckgBuf<TInt> lengthPckg(0);
+ TIpcArgs args(interfaceNameBuf, &lengthPckg, &iError);
+ SendReceive(EInterfaceDefaultSizeRequest, args);
+
+ HBufC8* interfaceDescriptorBuf = HBufC8::New(lengthPckg());
+ TPtr8 ptrToBuf(interfaceDescriptorBuf->Des());
+ TIpcArgs args2(&ptrToBuf);
+ SendReceive(EInterfaceDefaultRequest, args2);
+
+ QByteArray interfaceDescriptorByteArray((const char*)interfaceDescriptorBuf->Ptr(), interfaceDescriptorBuf->Length());
+ QDataStream out(interfaceDescriptorByteArray);
+ QServiceInterfaceDescriptor interfaceDescriptor;
+ out >> interfaceDescriptor;
+
+ delete interfaceNameBuf;
+ delete interfaceDescriptorBuf;
+
+ return interfaceDescriptor;
+ }
+
+bool RDatabaseManagerSession::SetInterfaceDefault(const QString &aServiceName, const QString &aInterfaceName)
+ {
+ TPtrC serviceNamePtr(reinterpret_cast<const TUint16*>(aServiceName.utf16()));
+ TPtrC interfaceNamePtr(reinterpret_cast<const TUint16*>(aInterfaceName.utf16()));
+ TIpcArgs args(&serviceNamePtr, &interfaceNamePtr, &iError);
+ SendReceive(ESetInterfaceDefault, args);
+
+ return (iError() == DBError::NoError);
+ }
+
+bool RDatabaseManagerSession::SetInterfaceDefault(const QServiceInterfaceDescriptor &aInterface)
+ {
+ QByteArray interfaceByteArray;
+ QDataStream in(&interfaceByteArray, QIODevice::WriteOnly);
+ in.setVersion(QDataStream::Qt_4_6);
+ in << aInterface;
+ TPtrC8 ptr8((TUint8 *)(interfaceByteArray.constData()), interfaceByteArray.size());
+ TIpcArgs args(&ptr8, &iError);
+ SendReceive(ESetInterfaceDefault2, args);
+
+ return (iError() == DBError::NoError);
+ }
+
+DBError RDatabaseManagerSession::LastError()
+ {
+ DBError error;
+ error.setError((DBError::ErrorCode)iError());
+ return error;
+ }
+
+void RDatabaseManagerSession::SetChangeNotificationsEnabled(bool aEnabled)
+ {
+ TIpcArgs args((aEnabled ? 1 : 0), &iError);
+ SendReceive(ESetChangeNotificationsEnabledRequest, args);
+ }
+
+void RDatabaseManagerSession::NotifyServiceSignal(TRequestStatus& aStatus)
+ {
+ iArgs.Set(0, &iServiceName);
+ iArgs.Set(1, &iState);
+ iArgs.Set(2, &iError);
+ SendReceive(ENotifyServiceSignalRequest, iArgs, aStatus);
+ }
+
+void RDatabaseManagerSession::CancelNotifyServiceSignal() const
+ {
+ SendReceive(ECancelNotifyServiceSignalRequest, TIpcArgs(NULL));
+ }
+
+#include "moc_databasemanager_symbian_p.cpp"
+
+QTM_END_NAMESPACE
+
+#endif //defined(__WINS__) && !defined(SYMBIAN_EMULATOR_SUPPORTS_PERPROCESS_WSD)
diff --git a/src/serviceframework/databasemanager_symbian_p.h b/src/serviceframework/databasemanager_symbian_p.h
new file mode 100644
index 00000000..dc4a9f91
--- /dev/null
+++ b/src/serviceframework/databasemanager_symbian_p.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DATABASEMANAGER_SYMBIAN_P_H
+#define DATABASEMANAGER_SYMBIAN_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#if defined(__WINS__) && !defined(SYMBIAN_EMULATOR_SUPPORTS_PERPROCESS_WSD)
+//Use DatabaseManager "directly" in emulators where per process WSD is not
+//supported.
+#include "databasemanager_p.h"
+#else //defined(__WINS__) && !defined(SYMBIAN_EMULATOR_SUPPORTS_PERPROCESS_WSD)
+
+#include "qserviceframeworkglobal.h"
+#include <QObject>
+#include <QList>
+
+#include <servicemetadata_p.h>
+#include "dberror_p.h"
+#include <e32base.h>
+
+
+QT_BEGIN_HEADER
+QTM_BEGIN_NAMESPACE
+
+class CDatabaseManagerServerThread;
+class QServiceFilter;
+typedef TPckgBuf<TInt> TError;
+
+class QServiceInterfaceDescriptor;
+
+class RDatabaseManagerSession : public RSessionBase
+ {
+ public:
+ enum DbScope{UserScope, SystemScope, UserOnlyScope};
+ RDatabaseManagerSession();
+
+ public:
+ TInt Connect();
+ void Close();
+ TVersion Version() const;
+
+ bool RegisterService(ServiceMetaDataResults& aService);
+ bool UnregisterService(const QString& aServiceName);
+ bool ServiceInitialized(const QString& aServiceName);
+
+ QList<QServiceInterfaceDescriptor> Interfaces(const QServiceFilter& aFilter);
+ QStringList ServiceNames(const QString& aInterfaceName);
+
+ QServiceInterfaceDescriptor InterfaceDefault(const QString& aInterfaceName);
+ bool SetInterfaceDefault(const QString& aServiceName, const QString& aInterfaceName);
+ bool SetInterfaceDefault(const QServiceInterfaceDescriptor& aInterface);
+
+ DBError LastError();
+
+ void SetChangeNotificationsEnabled(bool aEnabled);
+
+ void NotifyServiceSignal(TRequestStatus& aStatus);
+ void CancelNotifyServiceSignal() const;
+
+ public:
+ TBuf<255> iServiceName;
+ TPckgBuf<TInt> iState;
+
+ private:
+ TInt StartServer();
+
+ private:
+ TIpcArgs iArgs;
+ TError iError;
+ };
+
+class DatabaseManagerSignalMonitor;
+
+class Q_AUTOTEST_EXPORT DatabaseManager : public QObject
+{
+ Q_OBJECT
+
+ public:
+ enum DbScope{UserScope, SystemScope, UserOnlyScope};
+ DatabaseManager(void);
+ virtual ~DatabaseManager();
+
+ bool registerService(ServiceMetaDataResults &service, DbScope scope);
+ bool unregisterService(const QString &serviceName, DbScope scope);
+ bool serviceInitialized(const QString &serviceName, DbScope scope);
+
+ QList<QServiceInterfaceDescriptor> getInterfaces(const QServiceFilter &filter, DbScope scope);
+ QStringList getServiceNames(const QString &interfaceName, DbScope scope);
+
+ QServiceInterfaceDescriptor interfaceDefault(const QString &interfaceName, DbScope scope);
+ bool setInterfaceDefault(const QString &serviceName, const QString &interfaceName, DbScope scope);
+ bool setInterfaceDefault(const QServiceInterfaceDescriptor &interface, DbScope scope);
+
+ DBError lastError();
+
+ void setChangeNotificationsEnabled(DbScope scope, bool enabled);
+
+ signals:
+ void serviceAdded(const QString &serviceName, DatabaseManager::DbScope scope);
+ void serviceRemoved(const QString &serviceName, DatabaseManager::DbScope scope);
+
+ private:
+ enum State{EAdded, ERemoved};
+ void notifyServiceSignal();
+
+ private:
+ friend class DatabaseManagerSignalMonitor;
+ DatabaseManagerSignalMonitor* iDatabaseManagerSignalMonitor;
+ RDatabaseManagerSession iSession;
+ QServiceInterfaceDescriptor latestDescriptor(const QList<QServiceInterfaceDescriptor> &descriptors);
+};
+
+class DatabaseManagerSignalMonitor : public CActive
+{
+ public:
+ DatabaseManagerSignalMonitor(DatabaseManager& databaseManager, RDatabaseManagerSession& databaseManagerSession);
+ ~DatabaseManagerSignalMonitor();
+
+ protected:
+ void issueNotifyServiceSignal();
+
+ protected: // From CActive
+ void DoCancel();
+ void RunL();
+ private:
+ DatabaseManager& iDatabaseManager;
+ RDatabaseManagerSession& iDatabaseManagerSession;
+};
+
+QTM_END_NAMESPACE
+QT_END_HEADER
+
+#endif //defined(__WINS__) && !defined(SYMBIAN_EMULATOR_SUPPORTS_PERPROCESS_WSD)
+#endif //DATABASEMANAGER_SYMBIAN_P_H
diff --git a/src/serviceframework/databasemanagerserver_symbian/clientservercommon.h b/src/serviceframework/databasemanagerserver_symbian/clientservercommon.h
new file mode 100644
index 00000000..0e88f444
--- /dev/null
+++ b/src/serviceframework/databasemanagerserver_symbian/clientservercommon.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef CLIENTSERVERCOMMON_H_
+#define CLIENTSERVERCOMMON_H_
+
+#include <e32base.h>
+
+_LIT(KDatabaseManagerServerName, "!qsfwdatabasemanagerserver");
+_LIT(KDatabaseManagerServerProcess, "qsfwdatabasemanagerserver");
+
+const TUint KServerMajorVersionNumber = 0;
+const TUint KServerMinorVersionNumber = 1;
+const TUint KServerBuildVersionNumber = 1;
+
+IMPORT_C TInt StartThread(RThread& aServerThread);
+
+enum TDBServerRqst
+{
+ ERegisterServiceRequest,
+ EUnregisterServiceRequest,
+ EServiceInitializedRequest,
+ EGetInterfacesRequest,
+ EGetServiceNamesRequest,
+ EGetServiceNamesSizeRequest,
+ EGetInterfacesSizeRequest,
+ EInterfaceDefaultRequest,
+ EInterfaceDefaultSizeRequest,
+ ESetInterfaceDefault,
+ ESetInterfaceDefault2,
+ ESetChangeNotificationsEnabledRequest,
+ ENotifyServiceSignalRequest,
+ ECancelNotifyServiceSignalRequest
+};
+
+enum TDBServerRqstComplete
+{
+ ENotifySignalComplete = 1
+};
+
+#endif // CLIENTSERVERCOMMON_H_
+
+// End of file
diff --git a/src/serviceframework/databasemanagerserver_symbian/databasemanagerserver.cpp b/src/serviceframework/databasemanagerserver_symbian/databasemanagerserver.cpp
new file mode 100644
index 00000000..bc7107f1
--- /dev/null
+++ b/src/serviceframework/databasemanagerserver_symbian/databasemanagerserver.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "databasemanagerserver_p.h"
+#include "clientservercommon.h"
+#include "databasemanagersession_p.h"
+#include "servicedatabase_p.h"
+
+#include <QFileSystemWatcher>
+
+#include <QCoreApplication>
+//#include <QThread>
+
+QTM_BEGIN_NAMESPACE
+
+#define SEC_TOKEN 0x00000000
+
+static TInt Timeout(TAny *aObject);
+
+const TInt CDatabaseManagerServer::timeoutInterval = 30000000; // 30 seconds
+
+TInt Timeout(TAny *aObject)
+ {
+ ((CDatabaseManagerServer *)aObject)->Shutdown();
+ return 1;
+ }
+
+CDatabaseManagerServer::CDatabaseManagerServer()
+ : CServer2(EPriorityNormal, ESharableSessions)
+ , iSessionCount(0)
+ {
+ iPeriodic = CPeriodic::NewL(0);
+ iPeriodic->Start(timeoutInterval, timeoutInterval, TCallBack(Timeout, this));
+ iDb = new ServiceDatabase();
+ initDbPath();
+
+ iDatabaseManagerServerSignalHandler = new DatabaseManagerServerSignalHandler(this);
+ iWatcher = new QFileSystemWatcher();
+ QObject::connect(iWatcher, SIGNAL(directoryChanged(QString)),
+ iDatabaseManagerServerSignalHandler, SLOT(importChanged(QString)));
+
+ QString path = QDir::toNativeSeparators(QCoreApplication::applicationDirPath());
+ path += QDir::separator() + QString("import");
+
+ // Make the directory incase no xml services are installed
+ QDir dir;
+ dir.mkdir(path);
+ iWatcher->addPath(path);
+
+ DiscoverServices();
+
+ }
+
+CSession2* CDatabaseManagerServer::NewSessionL(const TVersion& aVersion, const RMessage2& /*aMessage*/) const
+ {
+ if (!User::QueryVersionSupported(TVersion(KServerMajorVersionNumber,
+ KServerMinorVersionNumber, KServerBuildVersionNumber), aVersion))
+ {
+ User::Leave(KErrNotSupported);
+ }
+
+ return CDatabaseManagerServerSession::NewL(*const_cast<CDatabaseManagerServer*>(this), iDb->databasePath());
+ }
+
+void CDatabaseManagerServer::PanicServer(TDatabaseManagerSerververPanic aPanic)
+ {
+ _LIT(KTxtServerPanic,"Database manager server panic");
+ User::Panic(KTxtServerPanic, aPanic);
+ }
+
+void CDatabaseManagerServer::IncreaseSessions()
+ {
+ iSessionCount++;
+ iPeriodic->Cancel();
+ }
+
+void CDatabaseManagerServer::DecreaseSessions()
+ {
+ iSessionCount--;
+ if (iSessionCount <= 0)
+ {
+ iPeriodic->Start(timeoutInterval, timeoutInterval, TCallBack(Timeout, this));
+ }
+ }
+
+void CDatabaseManagerServer::Shutdown()
+ {
+ QCoreApplication::exit(0);
+ }
+
+void CDatabaseManagerServer::initDbPath()
+ {
+ QString dbIdentifier = "_system";
+
+ QDir dir(QDir::toNativeSeparators(QCoreApplication::applicationDirPath()));
+ QString qtVersion(qVersion());
+ qtVersion = qtVersion.left(qtVersion.size() -2); //strip off patch version
+ QString dbName = QString("QtServiceFramework_") + qtVersion + dbIdentifier + QLatin1String(".db");
+ iDb->setDatabasePath(dir.path() + QDir::separator() + dbName);
+
+ // check if database is copied from Z drive; also valid for emulator
+ QFile dbFile(iDb->databasePath());
+ QFileInfo dbFileInfo(dbFile);
+ if (!dbFileInfo.exists()) {
+ // create folder first
+ if (!dbFileInfo.dir().exists())
+ QDir::root().mkpath(dbFileInfo.path());
+ // copy file from ROM
+ QFile romDb(QLatin1String("z:\\private\\2002ac7f\\") + dbFileInfo.fileName());
+ // why not use QFile::copy?
+ if (romDb.open(QIODevice::ReadOnly) && dbFile.open(QFile::WriteOnly)) {
+ QByteArray data = romDb.readAll();
+ dbFile.write(data);
+ dbFile.close();
+ romDb.close();
+ }
+ }
+
+ iDb->open();
+ }
+
+void CDatabaseManagerServer::DiscoverServices()
+{
+ QString path = QDir::toNativeSeparators(QCoreApplication::applicationDirPath());
+ QSettings settings(path + QDir::separator() + "autoimport.ini",
+ QSettings::NativeFormat);
+
+ QString imports = path + QDir::separator() + "import";
+
+ QDir dir(imports);
+ dir.setFilter(QDir::Files);
+ QStringList filters;
+ filters << "*.xml";
+ dir.setNameFilters(filters);
+ QSet<QString> seen;
+
+ QString tok = QString::number(SEC_TOKEN);
+
+ QStringList files = dir.entryList();
+ while(!files.isEmpty()){
+ QString file = files.takeFirst();
+ seen << file;
+
+ QFileInfo fileinfo(imports + QDir::separator() + file);
+
+ if(settings.contains(file)){
+ if(fileinfo.lastModified() == settings.value(file).toDateTime()) {
+ continue;
+ }
+ }
+ QFile *f = new QFile(imports + QDir::separator() + file);
+ // read contents, register
+ ServiceMetaData parser(f);
+ if (!parser.extractMetadata()) {
+ f->remove();
+ f->close();
+ continue;
+ }
+ const ServiceMetaDataResults data = parser.parseResults();
+ ServiceMetaDataResults results = parser.parseResults();
+ QString servicename = results.name;
+
+ if(iDb->registerService(results, tok)){
+ iDb->serviceInitialized(results.name, tok);
+ }
+ f->close();
+ settings.setValue(file, fileinfo.lastModified());
+ settings.setValue(file + "/service_name", servicename);
+ }
+
+ QSet<QString> oldfiles = settings.allKeys().toSet();
+ oldfiles -= seen;
+ foreach(QString old, oldfiles){
+ if(old.contains('/'))
+ continue;
+ QString servicename = settings.value(old + "/service_name").toString();
+ iDb->unregisterService(servicename, QString("Auto Registration"));
+ settings.remove(old);
+ }
+}
+
+void DatabaseManagerServerSignalHandler::importChanged(const QString& path)
+{
+ iDatabaseManagerServerSession->DiscoverServices();
+}
+
+
+QTM_END_NAMESPACE
+
+
+#include "moc_databasemanagerserver_p.cpp"
+// End of File
diff --git a/src/serviceframework/databasemanagerserver_symbian/databasemanagerserver.pan b/src/serviceframework/databasemanagerserver_symbian/databasemanagerserver.pan
new file mode 100644
index 00000000..9d9a93a1
--- /dev/null
+++ b/src/serviceframework/databasemanagerserver_symbian/databasemanagerserver.pan
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef DATABASEMANAGERSERVER_PAN_
+#define DATABASEMANAGERSERVER_PAN_
+
+// Panic category
+_LIT(KDatabaseManagerServer, "DatabaseManagerServer");
+_LIT(KUnknownOpCode, "Unknown op code");
+_LIT(KBadDescriptor, "Bad descriptor");
+
+enum TDatabaseManagerSerververPanic
+{
+ EBadRequest = 1,
+ ESrvCreateServer = 2,
+ ESvrStartServer = 3
+};
+
+#endif
+
+// End of File
diff --git a/src/serviceframework/databasemanagerserver_symbian/databasemanagerserver.pro b/src/serviceframework/databasemanagerserver_symbian/databasemanagerserver.pro
new file mode 100644
index 00000000..d52d60ac
--- /dev/null
+++ b/src/serviceframework/databasemanagerserver_symbian/databasemanagerserver.pro
@@ -0,0 +1,43 @@
+TEMPLATE = app
+TARGET = qsfwdatabasemanagerserver
+QT = core sql
+TARGET.UID3 = 0x2002AC7F
+
+CONFIG += no_icon
+
+DEFINES += QTM_SERVICEFW_SYMBIAN_DATABASEMANAGER_SERVER
+DEFINES += QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+
+SOURCES += databasemanagerservermain.cpp
+
+include(../../../common.pri)
+
+
+DEPENDPATH += ../
+INCLUDEPATH += ../
+
+HEADERS += servicemetadata_p.h \
+ servicedatabase_p.h \
+ qserviceplugininterface.h \
+ qabstractsecuritysession.h \
+ qserviceinterfacedescriptor.h \
+ qserviceinterfacedescriptor_p.h \
+ qservicefilter.h \
+ dberror_p.h \
+ databasemanagerserver_p.h \
+ databasemanagersession_p.h \
+ databasemanagersignalhandler_p.h
+
+SOURCES += servicemetadata.cpp \
+ servicedatabase.cpp \
+ qserviceplugininterface.cpp \
+ qabstractsecuritysession.cpp \
+ qserviceinterfacedescriptor.cpp \
+ qservicefilter.cpp \
+ dberror.cpp \
+ databasemanagerserver.cpp \
+ databasemanagersession.cpp \
+ databasemanagersignalhandler.cpp
+
+#ProtServ is needed so that the server can be in protected namespace (start with '!' -mark).
+TARGET.CAPABILITY = ProtServ
diff --git a/src/serviceframework/databasemanagerserver_symbian/databasemanagerserver_p.h b/src/serviceframework/databasemanagerserver_symbian/databasemanagerserver_p.h
new file mode 100644
index 00000000..5f57e9af
--- /dev/null
+++ b/src/serviceframework/databasemanagerserver_symbian/databasemanagerserver_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef CDATABASEMANAGERSERVER_H_
+#define CDATABASEMANAGERSERVER_H_
+
+#include <qserviceframeworkglobal.h>
+#include <e32base.h>
+#include <QObject>
+#include "databasemanagerserver.pan"
+
+class QFileSystemWatcher;
+
+//QTM_BEGIN_NAMESPACE
+namespace QtMobility {
+
+class DatabaseManagerServerSignalHandler;
+class ServiceDatabase;
+
+
+// needed for creating server thread.
+const TUint KDefaultHeapSize = 0x10000;
+
+class CDatabaseManagerServer : public CServer2
+ {
+ public:
+ CDatabaseManagerServer();
+ CSession2* NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const;
+
+ public:
+ static void PanicServer(TDatabaseManagerSerververPanic aPanic);
+
+ void IncreaseSessions();
+ void DecreaseSessions();
+
+ void Shutdown();
+
+ void DiscoverServices();
+
+ private:
+ void initDbPath();
+
+ static const TInt timeoutInterval;
+ int iSessionCount;
+ CPeriodic *iPeriodic;
+ ServiceDatabase *iDb;
+ QFileSystemWatcher *iWatcher;
+ DatabaseManagerServerSignalHandler *iDatabaseManagerServerSignalHandler;
+ };
+
+
+class DatabaseManagerServerSignalHandler : public QObject
+ {
+ Q_OBJECT
+
+ public:
+ DatabaseManagerServerSignalHandler(CDatabaseManagerServer *databaseManagerServerSession)
+ {
+ iDatabaseManagerServerSession = databaseManagerServerSession;
+ }
+
+ public Q_SLOTS:
+ void importChanged(const QString &path);
+
+ public:
+ CDatabaseManagerServer *iDatabaseManagerServerSession;
+ };
+
+//QTM_END_NAMESPACE
+}
+
+#endif
+
+// End of File
diff --git a/src/serviceframework/databasemanagerserver_symbian/databasemanagerservermain.cpp b/src/serviceframework/databasemanagerserver_symbian/databasemanagerservermain.cpp
new file mode 100644
index 00000000..86312746
--- /dev/null
+++ b/src/serviceframework/databasemanagerserver_symbian/databasemanagerservermain.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qserviceframeworkglobal.h>
+#include <QCoreApplication>
+#include <QFile>
+#include <QTextStream>
+#include "databasemanagerserver_p.h"
+#include "clientservercommon.h"
+
+QTM_USE_NAMESPACE
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ CDatabaseManagerServer* server = new CDatabaseManagerServer;
+ TInt err = server->Start(KDatabaseManagerServerName);
+ if (err != KErrAlreadyExists)
+ {
+ if (err != KErrNone)
+ {
+ CDatabaseManagerServer::PanicServer(ESvrStartServer);
+ }
+ RProcess::Rendezvous(err);
+
+ return app.exec();
+ }
+ return 0;
+}
+
diff --git a/src/serviceframework/databasemanagerserver_symbian/databasemanagersession.cpp b/src/serviceframework/databasemanagerserver_symbian/databasemanagersession.cpp
new file mode 100644
index 00000000..b5944f4d
--- /dev/null
+++ b/src/serviceframework/databasemanagerserver_symbian/databasemanagersession.cpp
@@ -0,0 +1,614 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "clientservercommon.h"
+#include "databasemanagersession_p.h"
+#include "databasemanagerserver.pan"
+#include "databasemanagersignalhandler_p.h"
+#include "servicedatabase_p.h"
+#include "databasemanagerserver_p.h"
+
+#include <QFileSystemWatcher>
+
+QTM_BEGIN_NAMESPACE
+
+bool lessThan(const QServiceInterfaceDescriptor &d1,
+ const QServiceInterfaceDescriptor &d2)
+ {
+ return (d1.majorVersion() < d2.majorVersion())
+ || ( d1.majorVersion() == d2.majorVersion()
+ && d1.minorVersion() < d2.minorVersion());
+ }
+
+CDatabaseManagerServerSession* CDatabaseManagerServerSession::NewL(CDatabaseManagerServer& aServer, QString dbPath)
+ {
+ CDatabaseManagerServerSession* self = CDatabaseManagerServerSession::NewLC(aServer, dbPath);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+CDatabaseManagerServerSession* CDatabaseManagerServerSession::NewLC(CDatabaseManagerServer& aServer, QString dbPath)
+ {
+ CDatabaseManagerServerSession* self = new (ELeave) CDatabaseManagerServerSession(aServer);
+ CleanupStack::PushL(self);
+ self->ConstructL(dbPath);
+ return self;
+ }
+
+void CDatabaseManagerServerSession::ConstructL(QString dbPath)
+ {
+ iDb = new ServiceDatabase();
+ iDb->setDatabasePath(dbPath);
+ openDb();
+
+ //initDbPath();
+ iDatabaseManagerSignalHandler = new DatabaseManagerSignalHandler(*this);
+
+ m_watcher = new QFileSystemWatcher();
+ QObject::connect(m_watcher, SIGNAL(fileChanged(QString)),
+ iDatabaseManagerSignalHandler, SLOT(databaseChanged(QString)));
+ }
+
+CDatabaseManagerServerSession::CDatabaseManagerServerSession(CDatabaseManagerServer& aServer)
+ : iServer(aServer),
+ iDatabaseManagerSignalHandler(NULL),
+ iDb(NULL),
+ m_watcher(NULL)
+ {
+ iServer.IncreaseSessions();
+ }
+
+CDatabaseManagerServerSession::~CDatabaseManagerServerSession()
+ {
+ delete iDatabaseManagerSignalHandler;
+ delete iDb;
+ delete iByteArray;
+ delete m_watcher;
+ iServer.DecreaseSessions();
+ }
+
+void CDatabaseManagerServerSession::ServiceL(const RMessage2& aMessage)
+ {
+ if (aMessage.Function() == ENotifyServiceSignalRequest)
+ {
+ NotifyServiceSignal(aMessage);
+ }
+ else
+ {
+ TRAPD(err, DispatchMessageL(aMessage));
+ aMessage.Complete(err);
+ }
+ }
+
+void CDatabaseManagerServerSession::DispatchMessageL(const RMessage2& aMessage)
+ {
+ switch (aMessage.Function())
+ {
+ case ERegisterServiceRequest:
+ User::LeaveIfError(RegisterServiceL(aMessage));
+ break;
+ case EUnregisterServiceRequest:
+ User::LeaveIfError(UnregisterServiceL(aMessage));
+ break;
+ case EServiceInitializedRequest:
+ User::LeaveIfError(ServiceInitializedL(aMessage));
+ break;
+ case EGetInterfacesRequest:
+ User::LeaveIfError(InterfacesL(aMessage));
+ break;
+ case EGetInterfacesSizeRequest:
+ User::LeaveIfError(InterfacesSizeL(aMessage));
+ break;
+ case EGetServiceNamesRequest:
+ User::LeaveIfError(ServiceNamesL(aMessage));
+ break;
+ case EGetServiceNamesSizeRequest:
+ User::LeaveIfError(ServiceNamesSizeL(aMessage));
+ break;
+ case EInterfaceDefaultRequest:
+ User::LeaveIfError(InterfaceDefaultL(aMessage));
+ break;
+ case ESetInterfaceDefault:
+ User::LeaveIfError(SetInterfaceDefaultL(aMessage));
+ break;
+ case ESetInterfaceDefault2:
+ User::LeaveIfError(SetInterfaceDefault2L(aMessage));
+ break;
+ case ESetChangeNotificationsEnabledRequest:
+ SetChangeNotificationsEnabled(aMessage);
+ break;
+ case EInterfaceDefaultSizeRequest:
+ User::LeaveIfError(InterfaceDefaultSize(aMessage));
+ break;
+ case ECancelNotifyServiceSignalRequest:
+ User::LeaveIfError(CancelNotifyServiceSignal(aMessage));
+ break;
+ default:
+ aMessage.Panic(KUnknownOpCode, KErrNotSupported);
+ break;
+ }
+ }
+
+TInt CDatabaseManagerServerSession::InterfaceDefaultSize(const RMessage2& aMessage)
+ {
+ TInt ret;
+ HBufC* defaultInterfaceBuf = HBufC::New(aMessage.GetDesLength(0));
+ if (!defaultInterfaceBuf)
+ return KErrNoMemory;
+
+ TPtr ptrToBuf(defaultInterfaceBuf->Des());
+ TRAP(ret, aMessage.ReadL(0, ptrToBuf));
+
+
+ QString interfaceName = QString::fromUtf16(ptrToBuf.Ptr(), ptrToBuf.Length());
+ QServiceInterfaceDescriptor descriptor;
+ descriptor = iDb->interfaceDefault(interfaceName);
+
+ iByteArray = new QByteArray();
+
+ QDataStream in(iByteArray, QIODevice::WriteOnly);
+ in.setVersion(QDataStream::Qt_4_6);
+ in << descriptor;
+
+ TPckgBuf<TInt> size(iByteArray->size());
+
+ aMessage.Write(1, size);
+ aMessage.Write(2, LastErrorCode());
+ delete defaultInterfaceBuf;
+
+ return ret;
+ }
+
+TInt CDatabaseManagerServerSession::InterfaceDefaultL(const RMessage2& aMessage)
+ {
+ TPtrC8 defaultInterfacePtr8((TUint8*)(iByteArray->constData()), iByteArray->size());
+ aMessage.Write(0, defaultInterfacePtr8);
+ delete iByteArray;
+ iByteArray = NULL;
+
+ return 0;
+ }
+
+void CDatabaseManagerServerSession::NotifyServiceSignal(const RMessage2& aMessage)
+ {
+ iMsg = aMessage;
+ iWaitingAsyncRequest = ETrue;
+ }
+
+TInt CDatabaseManagerServerSession::CancelNotifyServiceSignal(const RMessage2& /*aMessage*/)
+ {
+ if (iWaitingAsyncRequest)
+ {
+ iMsg.Complete(KErrCancel);
+ iWaitingAsyncRequest = EFalse;
+ }
+
+ return KErrNone;
+ }
+
+TInt CDatabaseManagerServerSession::RegisterServiceL(const RMessage2& aMessage)
+ {
+ QString securityToken;
+
+ TVendorId vendorId = aMessage.VendorId();
+ if (vendorId != 0)
+ {
+ securityToken = QString::number(vendorId);
+ }
+ else
+ {
+ securityToken = QString::number(aMessage.SecureId().iId);
+ }
+
+ TInt ret;
+ HBufC8* serviceMetaDataBuf8 = HBufC8::New(aMessage.GetDesLength(0));
+ if (!serviceMetaDataBuf8)
+ return KErrNoMemory;
+
+ TPtr8 ptrToBuf(serviceMetaDataBuf8->Des());
+ TRAP(ret, aMessage.ReadL(0, ptrToBuf));
+ if (ret != KErrNone)
+ {
+ iDb->lastError().setError(DBError::UnknownError);
+ aMessage.Write(1, LastErrorCode());
+ delete serviceMetaDataBuf8;
+ return ret;
+ }
+
+ QByteArray byteArray((const char*)ptrToBuf.Ptr(), ptrToBuf.Length());
+ QDataStream out(byteArray);
+ ServiceMetaDataResults results;
+ out >> results;
+
+ iDb->registerService(results, securityToken);
+
+ aMessage.Write(1, LastErrorCode());
+
+ delete serviceMetaDataBuf8;
+
+ return ret;
+ }
+
+TInt CDatabaseManagerServerSession::UnregisterServiceL(const RMessage2& aMessage)
+ {
+ QString securityToken;
+
+ TVendorId vendorId = aMessage.VendorId();
+ if (vendorId != 0)
+ {
+ securityToken = QString::number(vendorId);
+ }
+ else
+ {
+ securityToken = QString::number(aMessage.SecureId().iId);
+ }
+
+ TInt ret;
+ HBufC* serviceNameBuf = HBufC::New(aMessage.GetDesLength(0));
+ if (!serviceNameBuf)
+ return KErrNoMemory;
+
+ TPtr ptrToBuf(serviceNameBuf->Des());
+ TRAP(ret, aMessage.ReadL(0, ptrToBuf));
+ if (ret != KErrNone)
+ {
+ iDb->lastError().setError(DBError::UnknownError);
+ aMessage.Write(1, LastErrorCode());
+ delete serviceNameBuf;
+ return ret;
+ }
+
+ QString serviceName = QString::fromUtf16(ptrToBuf.Ptr(), ptrToBuf.Length());
+ iDb->unregisterService(serviceName, securityToken);
+
+ aMessage.Write(1, LastErrorCode());
+ delete serviceNameBuf;
+
+ return ret;
+ }
+
+TInt CDatabaseManagerServerSession::ServiceInitializedL(const RMessage2& aMessage)
+ {
+ QString securityToken;
+
+ TVendorId vendorId = aMessage.VendorId();
+ if (vendorId != 0)
+ {
+ securityToken = QString::number(vendorId);
+ }
+ else
+ {
+ securityToken = QString::number(aMessage.SecureId().iId);
+ }
+
+ TInt ret;
+ HBufC* serviceNameBuf = HBufC::New(aMessage.GetDesLength(0));
+ if (!serviceNameBuf)
+ return KErrNoMemory;
+
+ TPtr ptrToBuf(serviceNameBuf->Des());
+ TRAP(ret, aMessage.ReadL(0, ptrToBuf));
+ if (ret != KErrNone)
+ {
+ iDb->lastError().setError(DBError::UnknownError);
+ aMessage.Write(1, LastErrorCode());
+ delete serviceNameBuf;
+ return ret;
+ }
+
+ QString serviceName = QString::fromUtf16(ptrToBuf.Ptr(), ptrToBuf.Length());
+ iDb->serviceInitialized(serviceName, securityToken);
+
+ aMessage.Write(1, LastErrorCode());
+ delete serviceNameBuf;
+
+ return ret;
+ }
+
+TInt CDatabaseManagerServerSession::InterfacesSizeL(const RMessage2& aMessage)
+ {
+ TInt ret;
+ HBufC8* buf = HBufC8::New(aMessage.GetDesLength(0));
+ if (!buf)
+ return KErrNoMemory;
+
+ TPtr8 ptrToBuf(buf->Des());
+ TRAP(ret, aMessage.ReadL(0, ptrToBuf));
+ if (ret != KErrNone)
+ {
+ iDb->lastError().setError(DBError::UnknownError);
+ aMessage.Write(2, LastErrorCode());
+ delete buf;
+ return ret;
+ }
+
+ QByteArray byteArray((const char*)ptrToBuf.Ptr(), ptrToBuf.Length());
+ QDataStream out(byteArray);
+ QServiceFilter filter;
+ out >> filter;
+
+ QList<QServiceInterfaceDescriptor> interfaces = iDb->getInterfaces(filter);
+ iByteArray = new QByteArray();
+
+ QDataStream in(iByteArray, QIODevice::WriteOnly);
+ in.setVersion(QDataStream::Qt_4_6);
+ in << interfaces;
+
+ TPckgBuf<TInt> size(iByteArray->size());
+ aMessage.Write(1, size);
+ aMessage.Write(2, LastErrorCode());
+
+ delete buf;
+ return ret;
+ }
+
+TInt CDatabaseManagerServerSession::InterfacesL(const RMessage2& aMessage)
+ {
+ TPtrC8 interfacesPtr8((TUint8*)(iByteArray->constData()), iByteArray->size());
+ aMessage.Write(0, interfacesPtr8);
+ delete iByteArray;
+ iByteArray = NULL;
+
+ return 0;
+ }
+
+TInt CDatabaseManagerServerSession::ServiceNamesSizeL(const RMessage2& aMessage)
+ {
+ TInt ret;
+ HBufC* serviceNamesBuf = HBufC::New(aMessage.GetDesLength(0));
+ if (!serviceNamesBuf)
+ return KErrNoMemory;
+
+ TPtr ptrToBuf (serviceNamesBuf->Des());
+ TRAP(ret, aMessage.ReadL(0, ptrToBuf));
+ if (ret != KErrNone)
+ {
+ iDb->lastError().setError(DBError::UnknownError);
+ aMessage.Write(2, LastErrorCode());
+ delete serviceNamesBuf;
+ return ret;
+ }
+
+ QString interfaceName = QString::fromUtf16(ptrToBuf.Ptr(), ptrToBuf.Length());
+ QStringList serviceNames = iDb->getServiceNames(interfaceName);
+ iByteArray = new QByteArray();
+
+ QDataStream in(iByteArray, QIODevice::WriteOnly);
+ in.setVersion(QDataStream::Qt_4_6);
+ in << serviceNames;
+
+ TPckgBuf<TInt> size(iByteArray->size());
+ aMessage.Write(1, size);
+ aMessage.Write(2, LastErrorCode());
+ delete serviceNamesBuf;
+
+ return ret;
+ }
+
+TInt CDatabaseManagerServerSession::ServiceNamesL(const RMessage2& aMessage)
+ {
+ TPtrC8 ptr8((TUint8*)(iByteArray->constData()), iByteArray->size());
+ aMessage.Write(0, ptr8);
+ delete iByteArray;
+ iByteArray = NULL;
+
+ return 0;
+ }
+
+TInt CDatabaseManagerServerSession::SetInterfaceDefaultL(const RMessage2& aMessage)
+ {
+ TInt ret;
+ HBufC* serviceNameBuf = HBufC::New(aMessage.GetDesLength(0));
+ HBufC* interfaceNameBuf = HBufC::New(aMessage.GetDesLength(1));
+ if (!serviceNameBuf || !interfaceNameBuf)
+ return KErrNoMemory;
+
+ TPtr ptrToBuf(serviceNameBuf->Des());
+ TPtr ptrToBuf2(interfaceNameBuf->Des());
+
+ TRAP(ret, aMessage.ReadL(0, ptrToBuf));
+ TRAPD(ret2, aMessage.ReadL(1, ptrToBuf2));
+ if (ret != KErrNone || ret2 != KErrNone)
+ {
+ iDb->lastError().setError(DBError::UnknownError);
+ aMessage.Write(2, LastErrorCode());
+ delete serviceNameBuf;
+ delete interfaceNameBuf;
+ return (ret == KErrNone) ? ret2 : ret;
+ }
+
+ QString serviceName = QString::fromUtf16(ptrToBuf.Ptr(), ptrToBuf.Length());
+ QString interfaceName = QString::fromUtf16(ptrToBuf2.Ptr(), ptrToBuf2.Length());
+
+ QList<QServiceInterfaceDescriptor> descriptors;
+ QServiceFilter filter;
+ filter.setServiceName(serviceName);
+ filter.setInterface(interfaceName);
+ // Nothing should be returned, because we are checking on nonexistent service
+ descriptors = iDb->getInterfaces(filter);
+
+ //find the descriptor with the latest version
+ int latestIndex = 0;
+ for (int i = 1; i < descriptors.count(); ++i) {
+ if (lessThan(descriptors[latestIndex], descriptors[i]))
+ latestIndex = i;
+ }
+
+ if (!descriptors.isEmpty()) {
+ iDb->setInterfaceDefault(descriptors[latestIndex]);
+ }
+ else {
+ aMessage.Write(2, TError(DBError::NotFound));
+ delete serviceNameBuf;
+ delete interfaceNameBuf;
+ return KErrNotFound;
+ }
+
+ aMessage.Write(2, LastErrorCode());
+ delete serviceNameBuf;
+ delete interfaceNameBuf;
+
+ return ret;
+ }
+
+TInt CDatabaseManagerServerSession::SetInterfaceDefault2L(const RMessage2& aMessage)
+ {
+ TInt ret;
+ HBufC8* interfaceBuf = HBufC8::New(aMessage.GetDesLength(0));
+ if (!interfaceBuf)
+ return KErrNoMemory;
+
+ TPtr8 ptrToBuf(interfaceBuf->Des());
+ TRAP(ret, aMessage.ReadL(0, ptrToBuf));
+ if (ret != KErrNone)
+ {
+ iDb->lastError().setError(DBError::UnknownError);
+ aMessage.Write(1, LastErrorCode());
+ delete interfaceBuf;
+ return ret;
+ }
+
+ QByteArray interfaceDescriptorByteArray((const char*)ptrToBuf.Ptr(), ptrToBuf.Length());
+ QDataStream out(interfaceDescriptorByteArray);
+ QServiceInterfaceDescriptor interfaceDescriptor;
+ out >> interfaceDescriptor;
+
+ iDb->setInterfaceDefault(interfaceDescriptor);
+ aMessage.Write(1, LastErrorCode());
+ delete interfaceBuf;
+
+ return ret;
+ }
+
+void CDatabaseManagerServerSession::SetChangeNotificationsEnabled(const RMessage2& aMessage)
+ {
+
+ m_watcher->addPath(iDb->databasePath());
+
+ if (aMessage.Int0() == 1) // 1 == Notifications enabled
+ {
+ m_knownServices.clear();
+ m_knownServices = iDb->getServiceNames(QString());
+ }
+ else
+ {
+ m_watcher->removePath(iDb->databasePath());
+ m_knownServices.clear();
+ }
+
+ aMessage.Write(1, LastErrorCode());
+ }
+
+void CDatabaseManagerServerSession::databaseChanged(const QString &path)
+ {
+ QStringList currentServices = iDb->getServiceNames(QString());
+
+ if (currentServices == m_knownServices)
+ return;
+
+ QStringList newServices;
+ for (int i=0; i<currentServices.count(); i++) {
+ if (!m_knownServices.contains(currentServices[i]))
+ newServices << currentServices[i];
+ }
+
+ QStringList removedServices;
+ for (int i=0; i<m_knownServices.count(); i++) {
+ if (!currentServices.contains(m_knownServices[i]))
+ removedServices << m_knownServices[i];
+ }
+
+ m_knownServices = currentServices;
+ for (int i=0; i<newServices.count(); i++)
+ ServiceAdded(newServices[i]);
+ for (int i=0; i<removedServices.count(); i++)
+ ServiceRemoved(removedServices[i]);
+ }
+
+TError CDatabaseManagerServerSession::LastErrorCode()
+ {
+ return TError(iDb->lastError().code());
+ }
+
+void CDatabaseManagerServerSession::ServiceAdded(const QString& aServiceName)
+ {
+ if (iWaitingAsyncRequest)
+ {
+ TPckgBuf<TInt> state(0);
+ TPtrC str(reinterpret_cast<const TUint16*>(aServiceName.utf16()));
+ iMsg.Write(0, str);
+ iMsg.Write(1, state);
+ iMsg.Write(2, LastErrorCode());
+ iMsg.Complete(ENotifySignalComplete);
+ iWaitingAsyncRequest = EFalse;
+ }
+ }
+
+void CDatabaseManagerServerSession::ServiceRemoved(const QString& aServiceName)
+ {
+ if (iWaitingAsyncRequest)
+ {
+ TPckgBuf<TInt> state(1);
+ TPtrC str(reinterpret_cast<const TUint16*>(aServiceName.utf16()));
+ iMsg.Write(0, str);
+ iMsg.Write(1, state);
+ iMsg.Write(2, LastErrorCode());
+ iMsg.Complete(ENotifySignalComplete);
+ iWaitingAsyncRequest = EFalse;
+ }
+ }
+
+bool CDatabaseManagerServerSession::openDb()
+ {
+ if (iDb) {
+ if (iDb->isOpen()) {
+ return true;
+ } else {
+ return iDb->open();
+ }
+ }
+
+ return false;
+ }
+
+QTM_END_NAMESPACE
+
+// End of File
diff --git a/src/serviceframework/databasemanagerserver_symbian/databasemanagersession_p.h b/src/serviceframework/databasemanagerserver_symbian/databasemanagersession_p.h
new file mode 100644
index 00000000..abcc06ec
--- /dev/null
+++ b/src/serviceframework/databasemanagerserver_symbian/databasemanagersession_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef CDATABASEMANAGERSESSION_H_
+#define CDATABASEMANAGERSESSION_H_
+
+#include <qserviceframeworkglobal.h>
+#include <e32base.h>
+#include <QObject>
+#include <QStringList>
+
+class QFileSystemWatcher;
+
+QTM_BEGIN_NAMESPACE
+
+class CDatabaseManagerServer;
+class DatabaseManagerSignalHandler;
+class ServiceDatabase;
+
+typedef TPckgBuf<TInt> TError;
+
+class CDatabaseManagerServerSession : public CSession2
+ {
+ public:
+ static CDatabaseManagerServerSession* NewL(CDatabaseManagerServer& aServer, QString dbPath);
+ static CDatabaseManagerServerSession* NewLC(CDatabaseManagerServer& aServer, QString dbPath);
+ virtual ~CDatabaseManagerServerSession();
+
+ void ServiceL(const RMessage2& aMessage);
+ void DispatchMessageL(const RMessage2& aMessage);
+
+ TInt RegisterServiceL(const RMessage2& aMessage);
+ TInt UnregisterServiceL(const RMessage2& aMessage);
+ TInt ServiceInitializedL(const RMessage2& aMessage);
+ TInt InterfacesL(const RMessage2& aMessage);
+ TInt ServiceNamesL(const RMessage2& aMessage);
+ TInt InterfaceDefaultL(const RMessage2& aMessage);
+ TInt SetInterfaceDefaultL(const RMessage2& aMessage);
+ TInt SetInterfaceDefault2L(const RMessage2& aMessage);
+ void NotifyServiceSignal(const RMessage2& aMessage);
+ TInt CancelNotifyServiceSignal(const RMessage2& aMessage);
+ void SetChangeNotificationsEnabled(const RMessage2& aMessage);
+ TInt InterfaceDefaultSize(const RMessage2& aMessage);
+ TInt InterfacesSizeL(const RMessage2& aMessage);
+ TInt ServiceNamesSizeL(const RMessage2& aMessage);
+
+ void ServiceRemoved(const QString& aServiceName);
+ void ServiceAdded(const QString& aServiceName);
+ void databaseChanged(const QString &path);
+
+ private:
+ CDatabaseManagerServerSession(CDatabaseManagerServer& aServer);
+ void ConstructL(QString dbPath);
+ TError LastErrorCode();
+ bool openDb();
+
+ protected:
+ void PanicClient(const RMessage2& aMessage, TInt aPanic) const;
+
+ private:
+ CDatabaseManagerServer& iServer;
+ QByteArray* iByteArray;
+ TBool iWaitingAsyncRequest;
+ RMessage2 iMsg;
+ DatabaseManagerSignalHandler* iDatabaseManagerSignalHandler;
+ ServiceDatabase *iDb;
+ QStringList m_knownServices;
+ QFileSystemWatcher *m_watcher;
+ };
+
+QTM_END_NAMESPACE
+
+#endif
+
+// End of File
diff --git a/src/serviceframework/databasemanagerserver_symbian/databasemanagersignalhandler.cpp b/src/serviceframework/databasemanagerserver_symbian/databasemanagersignalhandler.cpp
new file mode 100644
index 00000000..830fb450
--- /dev/null
+++ b/src/serviceframework/databasemanagerserver_symbian/databasemanagersignalhandler.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "databasemanagersignalhandler_p.h"
+
+QTM_BEGIN_NAMESPACE
+
+DatabaseManagerSignalHandler::DatabaseManagerSignalHandler(CDatabaseManagerServerSession& databaseManagerServerSession)
+ : iDatabaseManagerServerSession(databaseManagerServerSession)
+{
+}
+
+void DatabaseManagerSignalHandler::databaseChanged(const QString &path)
+{
+ iDatabaseManagerServerSession.databaseChanged(path);
+}
+
+#include "moc_databasemanagersignalhandler_p.cpp"
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/databasemanagerserver_symbian/databasemanagersignalhandler_p.h b/src/serviceframework/databasemanagerserver_symbian/databasemanagersignalhandler_p.h
new file mode 100644
index 00000000..4345d76c
--- /dev/null
+++ b/src/serviceframework/databasemanagerserver_symbian/databasemanagersignalhandler_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef DATABASEMANAGERSIGNALHANDLER_H
+#define DATABASEMANAGERSIGNALHANDLER_H
+
+#include <QObject>
+#include "databasemanagersession_p.h"
+
+QTM_BEGIN_NAMESPACE
+
+class DatabaseManagerSignalHandler : public QObject
+ {
+ Q_OBJECT
+
+ public:
+ DatabaseManagerSignalHandler(CDatabaseManagerServerSession& databaseManagerServerSession);
+
+ public Q_SLOTS:
+ void databaseChanged(const QString &path);
+
+ public:
+ CDatabaseManagerServerSession& iDatabaseManagerServerSession;
+ };
+
+QTM_END_NAMESPACE
+
+#endif
+
+// End of File
+
diff --git a/src/serviceframework/dberror.cpp b/src/serviceframework/dberror.cpp
new file mode 100644
index 00000000..c9691a03
--- /dev/null
+++ b/src/serviceframework/dberror.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "dberror_p.h"
+
+QTM_BEGIN_NAMESPACE
+
+DBError::DBError()
+{
+ setError(NoError);
+}
+
+void DBError::setError(ErrorCode error, const QString &text)
+{
+ m_error = error;
+ switch (error) {
+ case (NoError):
+ m_text = QLatin1String("No error");
+ break;
+ case(DatabaseNotOpen):
+ m_text = QLatin1String("Database not open");
+ break;
+ case(InvalidDatabaseConnection):
+ m_text = QLatin1String("Invalid database connection");
+ break;
+ case(ExternalIfaceIDFound):
+ m_text = QLatin1String("External InterfaceID found");
+ break;
+ case(SqlError):
+ case(NotFound):
+ case(LocationAlreadyRegistered):
+ case(IfaceImplAlreadyRegistered):
+ case(CannotCreateDbDir):
+ case(InvalidDescriptorScope):
+ case(IfaceIDNotExternal):
+ case(InvalidDatabaseFile):
+ case(NoWritePermissions):
+ case(CannotOpenServiceDb):
+ m_text = text;
+ break;
+ default:
+ m_text= QLatin1String("Unknown error");
+ m_error = UnknownError;
+ }
+}
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/dberror_p.h b/src/serviceframework/dberror_p.h
new file mode 100644
index 00000000..1a02a05d
--- /dev/null
+++ b/src/serviceframework/dberror_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DBERROR_H
+#define DBERROR_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qserviceframeworkglobal.h"
+#include <QString>
+
+QTM_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT DBError
+{
+ public:
+ enum ErrorCode {
+ NoError,
+ DatabaseNotOpen = -2000, //A connection with the database has not been opened
+ // database needs to be opened before any operations take place
+ InvalidDatabaseConnection, //The database connection does not have a valid driver
+ LocationAlreadyRegistered, //A service location has already been registered.
+ IfaceImplAlreadyRegistered, //An interface implementation by a given service is already registered to that service
+ NotFound,
+ SqlError, //An Sql error occurred.
+ IfaceIDNotExternal, //InterfaceID does not refer to an external interface implementation
+ CannotCreateDbDir, //Directory to contain database could not be created(usu a permissions issue)
+ CannotOpenServiceDb, //service database cannot be opened(usually a permissions issue)
+ ExternalIfaceIDFound, //Notification for interfaceDefault() on a user scope database
+ // to indicate that a default refers to an interface implementation in the
+ // system scope database
+ InvalidDescriptorScope, //Notification for setInterfaceDefault() on a system scope database
+ // to indicate that a user scope descriptor cannot be used
+ // with a system scope database.
+ InvalidDatabaseFile, //database file is corrupted or not a valid database
+ NoWritePermissions, //trying to perform a write operation without sufficient permissions
+ UnknownError
+ };
+ DBError();
+ void setError(ErrorCode error, const QString &errorText = QString());
+ void setSQLError(const QString &errorText) {
+ m_error = SqlError;
+ m_text = errorText;
+ }
+ void setNotFoundError(const QString &errorText) {
+ m_error = NotFound;
+ m_text = errorText;
+ }
+ QString text() const { return m_text; }
+ ErrorCode code() const { return m_error; }
+ private:
+ QString m_text;
+ ErrorCode m_error;
+};
+QTM_END_NAMESPACE
+
+#endif //DBERROR_H
diff --git a/src/serviceframework/ipc/instancemanager.cpp b/src/serviceframework/ipc/instancemanager.cpp
new file mode 100644
index 00000000..549a00d5
--- /dev/null
+++ b/src/serviceframework/ipc/instancemanager.cpp
@@ -0,0 +1,247 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qserviceframeworkglobal.h>
+#include <QTimer>
+#include "instancemanager_p.h"
+#include "qremoteserviceregisterentry_p.h"
+
+QTM_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC(InstanceManager, typeRegister);
+
+/*!
+ \internal
+
+ Returns the instance manager for the service process
+ \since 1.1
+*/
+InstanceManager* InstanceManager::instance()
+{
+ return typeRegister();
+}
+
+InstanceManager::InstanceManager(QObject *parent)
+ : QObject(parent)
+{
+}
+
+InstanceManager::~InstanceManager()
+{
+ QList<QRemoteServiceRegister::Entry> allEntries = metaMap.keys();
+ while (!allEntries.isEmpty()) {
+ ServiceIdentDescriptor descr = metaMap.take(allEntries.takeFirst());
+ if (descr.entryData->instanceType == QRemoteServiceRegister::GlobalInstance) {
+ if (descr.globalInstance)
+ QTimer::singleShot(0, descr.globalInstance, SLOT(deleteLater())); // Symbian issue, use timer
+ descr.globalInstance = 0;
+ } else {
+ QList<QUuid> allUuids = descr.individualInstances.keys();
+ while (!allUuids.isEmpty()) {
+ QTimer::singleShot(0, descr.individualInstances.take(allUuids.takeFirst()), SLOT(deleteLater())); // Symbian issue
+ }
+ }
+ }
+
+}
+
+/*!
+ \internal
+
+ Adds an entry to the map of service identifiers
+ \since 1.1
+*/
+bool InstanceManager::addType(const QRemoteServiceRegister::Entry& e)
+{
+ QMutexLocker ml(&lock);
+
+ if (metaMap.contains(e)) {
+ qWarning() << "Service" << e.serviceName() << "(" << e.interfaceName()
+ << ", " << e.version() << ")" << "already registered";
+ } else {
+ ServiceIdentDescriptor d;
+ d.entryData = e.d;
+ metaMap.insert(e, d);
+ return true;
+ }
+ return false;
+}
+
+/*!
+ \internal
+
+ Returns the metaobject of a registered service object identified by its \a entry
+ \since 1.1
+*/
+const QMetaObject* InstanceManager::metaObject(const QRemoteServiceRegister::Entry& entry) const
+{
+ QMutexLocker ml(&lock);
+ if (metaMap.contains(entry)) {
+ return metaMap[entry].entryData->meta;
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ \internal
+
+ Returns a list of all the registered entries
+ \since 1.1
+*/
+QList<QRemoteServiceRegister::Entry> InstanceManager::allEntries() const
+{
+ QMutexLocker ml(&lock);
+ return metaMap.keys();
+}
+
+/*!
+ \internal
+
+ Instance manager takes ownership of service instance. Returns a null pointer
+ if \a entry cannot be mapped to a known meta object. The \a instanceId will
+ contain the unique ID for the new service instance.
+ \since 1.1
+*/
+QObject* InstanceManager::createObjectInstance(const QRemoteServiceRegister::Entry& entry, QUuid& instanceId)
+{
+ instanceId = QUuid();
+ QMutexLocker ml(&lock);
+ if (!metaMap.contains(entry))
+ return 0;
+
+ QObject* service = 0;
+ ServiceIdentDescriptor& descr = metaMap[entry];
+
+ if (descr.entryData->instanceType == QRemoteServiceRegister::GlobalInstance) {
+ if (descr.globalInstance) {
+ service = descr.globalInstance;
+ instanceId = descr.globalId;
+ descr.globalRefCount++;
+ } else {
+ service = (*descr.entryData->cptr)();
+ if (!service)
+ return 0;
+
+ descr.globalInstance = service;
+ descr.globalId = instanceId = QUuid::createUuid();
+ descr.globalRefCount = 1;
+ }
+ } else {
+ service = (*descr.entryData->cptr)();
+ if (!service)
+ return 0;
+ instanceId = QUuid::createUuid();
+ descr.individualInstances.insert(instanceId, service);
+ }
+
+ return service;
+}
+
+/*!
+ \internal
+
+ The associated service object instance will be deleted in the service process.
+ Removes an instance with \a instanceId from a map of remote service descriptors
+ using the \a entry as the key.
+
+ Emits instanceClosed() and allInstancesClosed() if no more instances are open
+ \since 1.1
+*/
+void InstanceManager::removeObjectInstance(const QRemoteServiceRegister::Entry& entry, const QUuid& instanceId)
+{
+ QMutexLocker ml(&lock);
+ if (!metaMap.contains(entry))
+ return;
+
+ ServiceIdentDescriptor& descr = metaMap[entry];
+ if (descr.entryData->instanceType == QRemoteServiceRegister::GlobalInstance) {
+ if (descr.globalRefCount < 1)
+ return;
+
+ if (descr.globalRefCount == 1) {
+ if (descr.globalInstance)
+ QTimer::singleShot(0, descr.globalInstance, SLOT(deleteLater()));
+ descr.globalInstance = 0;
+ descr.globalId = QUuid();
+ descr.globalRefCount = 0;
+ emit instanceClosed(entry);
+ emit instanceClosed(entry, instanceId); //internal use
+ } else {
+ descr.globalRefCount--;
+ }
+ } else {
+ QObject* service = descr.individualInstances.take(instanceId);
+ if (service) {
+ QTimer::singleShot(0, service, SLOT(deleteLater())); // symbian issue
+ emit instanceClosed(entry);
+ emit instanceClosed(entry, instanceId); //internal use
+ }
+ }
+
+ // Check that no instances are open
+ if (totalInstances() < 1)
+ emit allInstancesClosed();
+}
+
+/*!
+ \internal
+
+ Provides a count of how many global and private instances are currently open
+ \since 1.1
+*/
+int InstanceManager::totalInstances() const
+{
+ int total = 0;
+
+ QList<QRemoteServiceRegister::Entry> allEntries = metaMap.keys();
+ foreach (const QRemoteServiceRegister::Entry& entry, allEntries) {
+ ServiceIdentDescriptor descr = metaMap[entry];
+ total += descr.globalRefCount;
+ total += descr.individualInstances.size();
+ }
+
+ return total;
+}
+
+#include "moc_instancemanager_p.cpp"
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/instancemanager_p.h b/src/serviceframework/ipc/instancemanager_p.h
new file mode 100644
index 00000000..a27efbc2
--- /dev/null
+++ b/src/serviceframework/ipc/instancemanager_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERVICE_INSTANCE_MANAGER
+#define QSERVICE_INSTANCE_MANAGER
+
+#include <qserviceframeworkglobal.h>
+#include "qremoteserviceregister.h"
+#include "qremoteserviceregisterentry_p.h"
+#include <QHash>
+#include <QMutexLocker>
+#include <QMetaObject>
+#include <QMetaClassInfo>
+#include <QUuid>
+#include <QDebug>
+
+QTM_BEGIN_NAMESPACE
+
+struct ServiceIdentDescriptor
+{
+ ServiceIdentDescriptor() : globalInstance(0), globalRefCount(0)
+ {
+ }
+
+ QExplicitlySharedDataPointer<QRemoteServiceRegisterEntryPrivate> entryData;
+
+ QHash<QUuid, QObject*> individualInstances;
+ QObject* globalInstance;
+ QUuid globalId;
+ int globalRefCount;
+};
+
+class Q_AUTOTEST_EXPORT InstanceManager : public QObject
+{
+ Q_OBJECT
+public:
+ InstanceManager(QObject *parent = 0);
+ ~InstanceManager();
+
+ bool addType(const QRemoteServiceRegister::Entry& entry);
+
+ const QMetaObject* metaObject(const QRemoteServiceRegister::Entry& ident) const;
+ QList<QRemoteServiceRegister::Entry> allEntries() const;
+
+ int totalInstances() const;
+
+ QObject* createObjectInstance(const QRemoteServiceRegister::Entry& entry, QUuid& instanceId);
+ void removeObjectInstance(const QRemoteServiceRegister::Entry& entry, const QUuid& instanceId);
+
+ static InstanceManager* instance();
+
+Q_SIGNALS:
+ void allInstancesClosed();
+ void instanceClosed(const QRemoteServiceRegister::Entry&);
+ void instanceClosed(const QRemoteServiceRegister::Entry&, const QUuid&);
+
+private:
+ mutable QMutex lock;
+ QHash<QRemoteServiceRegister::Entry, ServiceIdentDescriptor> metaMap;
+};
+
+
+
+QTM_END_NAMESPACE
+
+
+#endif //QSERVICE_INSTANCE_MANAGER
diff --git a/src/serviceframework/ipc/ipc.pri b/src/serviceframework/ipc/ipc.pri
new file mode 100644
index 00000000..58d63307
--- /dev/null
+++ b/src/serviceframework/ipc/ipc.pri
@@ -0,0 +1,46 @@
+INCLUDEPATH += ipc
+symbian {
+ PRIVATE_HEADERS += ipc/qremoteserviceregister_s60_p.h \
+ ipc/objectendpoint_p.h
+ SOURCES += ipc/qremoteserviceregister_s60.cpp \
+ ipc/objectendpoint.cpp
+}
+else {
+ contains(QT_CONFIG,dbus) {
+ QT += dbus \
+ network
+ PRIVATE_HEADERS += ipc/qremoteserviceregister_dbus_p.h \
+ ipc/objectendpoint_dbus_p.h \
+ ipc/qservicemetaobject_dbus_p.h
+ SOURCES += ipc/qremoteserviceregister_dbus_p.cpp \
+ ipc/objectendpoint_dbus.cpp \
+ ipc/qservicemetaobject_dbus.cpp
+ }
+ else {
+ QT += network
+ PRIVATE_HEADERS += ipc/qremoteserviceregister_ls_p.h \
+ ipc/objectendpoint_p.h
+ SOURCES += ipc/qremoteserviceregister_ls_p.cpp \
+ ipc/objectendpoint.cpp
+ }
+}
+
+PRIVATE_HEADERS += ipc/qslotinvoker_p.h \
+ ipc/qsignalintercepter_p.h \
+ ipc/instancemanager_p.h \
+ ipc/qservicepackage_p.h \
+ ipc/proxyobject_p.h \
+ ipc/ipcendpoint_p.h \
+ ipc/qremoteserviceregister_p.h \
+ ipc/qremoteserviceregisterentry_p.h \
+ ipc/qmetaobjectbuilder_p.h
+
+SOURCES += ipc/qslotinvoker.cpp \
+ ipc/qsignalintercepter.cpp \
+ ipc/instancemanager.cpp \
+ ipc/qservicepackage.cpp \
+ ipc/proxyobject.cpp \
+ ipc/ipcendpoint.cpp \
+ ipc/qremoteserviceregister_p.cpp \
+ ipc/qmetaobjectbuilder.cpp
+
diff --git a/src/serviceframework/ipc/ipcendpoint.cpp b/src/serviceframework/ipc/ipcendpoint.cpp
new file mode 100644
index 00000000..43578455
--- /dev/null
+++ b/src/serviceframework/ipc/ipcendpoint.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "ipcendpoint_p.h"
+
+QTM_BEGIN_NAMESPACE
+/*!
+ QServiceIpcEndPoint
+*/
+QServiceIpcEndPoint::QServiceIpcEndPoint(QObject* parent)
+ : QObject( parent )
+{
+}
+
+QServiceIpcEndPoint::~QServiceIpcEndPoint()
+{
+ incoming.clear();
+}
+
+bool QServiceIpcEndPoint::packageAvailable() const
+{
+ return !incoming.isEmpty();
+}
+
+QServicePackage QServiceIpcEndPoint::nextPackage()
+{
+ if (!incoming.isEmpty())
+ return incoming.dequeue();
+ return QServicePackage();
+}
+
+void QServiceIpcEndPoint::writePackage(QServicePackage newPackage)
+{
+ flushPackage(newPackage);
+}
+
+#include "moc_ipcendpoint_p.cpp"
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/ipcendpoint_p.h b/src/serviceframework/ipc/ipcendpoint_p.h
new file mode 100644
index 00000000..faf445ab
--- /dev/null
+++ b/src/serviceframework/ipc/ipcendpoint_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q_SERVICECOMM_P_H
+#define Q_SERVICECOMM_P_H
+
+#include "qserviceframeworkglobal.h"
+#include <QObject>
+#include <QQueue>
+
+#include "qservicepackage_p.h"
+
+QTM_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QServiceIpcEndPoint : public QObject
+{
+ Q_OBJECT
+public:
+ QServiceIpcEndPoint(QObject* object = 0);
+ virtual ~QServiceIpcEndPoint();
+
+ bool packageAvailable() const;
+ QServicePackage nextPackage();
+
+ void writePackage(QServicePackage newPackage);
+
+Q_SIGNALS:
+ void readyRead();
+ void disconnected();
+
+protected:
+ virtual void flushPackage(const QServicePackage& out) = 0;
+
+ QQueue<QServicePackage> incoming;
+};
+
+
+QTM_END_NAMESPACE
+
+#endif //Q_SERVICECOMM_P_H
diff --git a/src/serviceframework/ipc/metaobjectbuilder.pri b/src/serviceframework/ipc/metaobjectbuilder.pri
new file mode 100644
index 00000000..561bddb5
--- /dev/null
+++ b/src/serviceframework/ipc/metaobjectbuilder.pri
@@ -0,0 +1,12 @@
+#check version for 4.7 ...
+contains(QT_MAJOR_VERSION, 4):lessThan(QT_MINOR_VERSION, 8) {
+ OBJECTBUILDER_INCLUDEPATH += ipc/metaobjectbuilder47
+ OBJECTBUILDER_DEPENDPATH += ipc/metaobjectbuilder47
+ OBJECTBUILDER_HEADERS += ipc/metaobjectbuilder47/qmetaobjectbuilder_p.h
+ OBJECTBUILDER_SOURCES += ipc/metaobjectbuilder47/qmetaobjectbuilder.cpp
+} else {
+ OBJECTBUILDER_INCLUDEPATH += ipc/metaobjectbuilder
+ OBJECTBUILDER_DEPENDPATH += ipc/metaobjectbuilder
+ OBJECTBUILDER_HEADERS += ipc/metaobjectbuilder/qmetaobjectbuilder_p.h
+ OBJECTBUILDER_SOURCES += ipc/metaobjectbuilder/qmetaobjectbuilder.cpp
+}
diff --git a/src/serviceframework/ipc/objectendpoint.cpp b/src/serviceframework/ipc/objectendpoint.cpp
new file mode 100644
index 00000000..3edd7984
--- /dev/null
+++ b/src/serviceframework/ipc/objectendpoint.cpp
@@ -0,0 +1,636 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "objectendpoint_p.h"
+#include "instancemanager_p.h"
+#include "qmetaobjectbuilder_p.h"
+#include "proxyobject_p.h"
+#include "qsignalintercepter_p.h"
+#include <QTimer>
+#include <QEventLoop>
+#include <QEvent>
+#include <QVarLengthArray>
+#include <QTime>
+#include <QCoreApplication>
+
+QTM_BEGIN_NAMESPACE
+
+class Response
+{
+public:
+ Response() : isFinished(false), result(0)
+ { }
+
+ bool isFinished;
+ void* result;
+};
+
+typedef QHash<QUuid, Response*> Replies;
+Q_GLOBAL_STATIC(Replies, openRequests);
+
+class ServiceSignalIntercepter : public QSignalIntercepter
+{
+ //Do not put Q_OBJECT here
+public:
+ ServiceSignalIntercepter(QObject* sender, const QByteArray& signal,
+ ObjectEndPoint* parent)
+ : QSignalIntercepter(sender, signal, parent), endPoint(parent)
+ {
+
+ }
+
+ void setMetaIndex(int index)
+ {
+ metaIndex = index;
+ }
+
+protected:
+ void activated( const QList<QVariant>& args )
+ {
+ //qDebug() << signal() << "emitted." << args;
+ endPoint->invokeRemote(metaIndex, args, QMetaType::Void);
+ }
+private:
+ ObjectEndPoint* endPoint;
+ int metaIndex;
+
+};
+
+class ObjectEndPointPrivate
+{
+public:
+ ObjectEndPointPrivate()
+ {
+ }
+
+ ~ObjectEndPointPrivate()
+ {
+ }
+
+ //service side
+ void setupSignalIntercepters(QObject * service)
+ {
+ Q_ASSERT(endPointType == ObjectEndPoint::Service);
+
+ //create a signal intercepter for each signal
+ //offered by service
+ //exclude QObject signals
+ const QMetaObject* mo = service->metaObject();
+ while (mo && strcmp(mo->className(), "QObject"))
+ {
+ for (int i = mo->methodOffset(); i < mo->methodCount(); ++i) {
+ const QMetaMethod method = mo->method(i);
+ if (method.methodType() == QMetaMethod::Signal) {
+ QByteArray signal = method.signature();
+ //add '2' for signal - see QSIGNAL_CODE
+ ServiceSignalIntercepter* intercept =
+ new ServiceSignalIntercepter(service, "2"+signal, parent );
+ intercept->setMetaIndex(i);
+ }
+ }
+ mo = mo->superClass();
+ }
+ }
+
+ /*!
+ Activate slots connected to given signal. Unfortunately we can only do this
+ using the signal index relative to the meta object defining the signal.
+ */
+ int triggerConnectedSlots(QObject* service, const QMetaObject* meta, int id, void **args)
+ {
+ Q_ASSERT(endPointType == ObjectEndPoint::Client);
+
+ const QMetaObject* parentMeta = meta->superClass();
+ if (parentMeta)
+ id = triggerConnectedSlots(service, parentMeta, id, args);
+
+ if (id < 0)
+ return id;
+
+ const int methodsThisType = meta->methodCount() - meta->methodOffset();
+ if (id >= 0 && id < methodsThisType)
+ QMetaObject::activate(service, meta, id, args);
+
+ id -= methodsThisType;
+ return id;
+ }
+
+ //used on client and service side
+ ObjectEndPoint::Type endPointType;
+ ObjectEndPoint* parent;
+
+ //used on service side
+ QRemoteServiceRegister::Entry entry;
+ QUuid serviceInstanceId;
+};
+
+ObjectEndPoint::ObjectEndPoint(Type type, QServiceIpcEndPoint* comm, QObject* parent)
+ : QObject(parent), dispatch(comm), service(0)
+{
+ Q_ASSERT(dispatch);
+ d = new ObjectEndPointPrivate;
+ d->parent = this;
+ d->endPointType = type;
+
+ dispatch->setParent(this);
+ connect(dispatch, SIGNAL(readyRead()), this, SLOT(newPackageReady()), Qt::QueuedConnection);
+ connect(dispatch, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::QueuedConnection);
+ if (type == Client) {
+ return; //we are waiting for conctructProxy() call
+ } else {
+ if (dispatch->packageAvailable())
+ QTimer::singleShot(0, this, SLOT(newPackageReady()));
+ }
+}
+
+ObjectEndPoint::~ObjectEndPoint()
+{
+ delete d;
+}
+
+void ObjectEndPoint::disconnected()
+{
+ if (d->endPointType == Service) {
+ InstanceManager::instance()->removeObjectInstance(d->entry, d->serviceInstanceId);
+ }
+ // deleteLater on symbian does not function properly from disconnect()
+ // maybe disconnect comes in on a thread? Call from timer works.
+ QTimer::singleShot(0, this, SLOT(deleteLater()));
+}
+
+/*
+ Client requests proxy object. The proxy is owned by calling
+ code and this object must clean itself up upon destruction of
+ proxy.
+*/
+QObject* ObjectEndPoint::constructProxy(const QRemoteServiceRegister::Entry & entry)
+{
+ //client side
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
+
+ //ask for serialized meta object
+ //get proxy based on meta object
+ //return meta object
+ QServicePackage p;
+ p.d = new QServicePackagePrivate();
+ p.d->messageId = QUuid::createUuid();
+ p.d->entry = entry;
+
+ Response* response = new Response();
+ openRequests()->insert(p.d->messageId, response);
+
+ dispatch->writePackage(p);
+ waitForResponse(p.d->messageId);
+
+ if (response->isFinished) {
+ if (response->result == 0)
+ qWarning() << "Request for remote service failed";
+ else
+ service = reinterpret_cast<QServiceProxy* >(response->result);
+ } else {
+ qDebug() << "response passed but not finished";
+ return 0;
+ }
+
+ openRequests()->take(p.d->messageId);
+ delete response;
+
+ return service;
+}
+
+void ObjectEndPoint::newPackageReady()
+{
+ //client and service side
+
+ while (dispatch->packageAvailable())
+ {
+ QServicePackage p = dispatch->nextPackage();
+ if (!p.isValid())
+ continue;
+
+ switch (p.d->packageType) {
+ case QServicePackage::ObjectCreation:
+ objectRequest(p);
+ break;
+ case QServicePackage::MethodCall:
+ methodCall(p);
+ break;
+ case QServicePackage::PropertyCall:
+ propertyCall(p);
+ break;
+ default:
+ qWarning() << "Unknown package type received.";
+ }
+ }
+}
+
+void ObjectEndPoint::propertyCall(const QServicePackage& p)
+{
+ if (p.d->responseType == QServicePackage::NotAResponse) {
+ //service side
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Service);
+
+ QByteArray data = p.d->payload.toByteArray();
+ QDataStream stream(&data, QIODevice::ReadOnly);
+ int metaIndex = -1;
+ QVariant arg;
+ int callType;
+ stream >> metaIndex;
+ stream >> arg;
+ stream >> callType;
+ const QMetaObject::Call c = (QMetaObject::Call) callType;
+
+ QVariant result;
+ QMetaProperty property = service->metaObject()->property(metaIndex);
+ if (property.isValid()) {
+ switch (c) {
+ case QMetaObject::ReadProperty:
+ result = property.read(service);
+ break;
+ case QMetaObject::WriteProperty:
+ property.write(service, arg);
+ break;
+ case QMetaObject::ResetProperty:
+ property.reset(service);
+ break;
+ default:
+ break;
+
+ }
+ }
+
+ if (c == QMetaObject::ReadProperty) {
+ QServicePackage response = p.createResponse();
+ if (property.isValid()) {
+ response.d->responseType = QServicePackage::Success;
+ response.d->payload = result;
+ } else {
+ response.d->responseType = QServicePackage::Failed;
+ }
+ dispatch->writePackage(response);
+ }
+ } else {
+ //client side
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
+ Response* response = openRequests()->value(p.d->messageId);
+ response->isFinished = true;
+ if (p.d->responseType == QServicePackage::Failed) {
+ response->result = 0;
+ QTimer::singleShot(0, this, SIGNAL(pendingRequestFinished()));
+ qWarning() << "Service method call failed";
+ return;
+ }
+ QVariant* variant = new QVariant(p.d->payload);
+ response->result = reinterpret_cast<void *>(variant);
+
+ QTimer::singleShot(0, this, SIGNAL(pendingRequestFinished()));
+ }
+}
+
+void ObjectEndPoint::objectRequest(const QServicePackage& p)
+{
+ if (p.d->responseType != QServicePackage::NotAResponse ) {
+ //client side
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
+
+ Response* response = openRequests()->value(p.d->messageId);
+ if (p.d->responseType == QServicePackage::Failed) {
+ response->result = 0;
+ response->isFinished = true;
+ QTimer::singleShot(0, this, SIGNAL(pendingRequestFinished()));
+ qWarning() << "Service instantiation failed";
+ return;
+ }
+ //deserialize meta object and
+ //create proxy object
+ QServiceProxy* proxy = new QServiceProxy(p.d->payload.toByteArray(), this);
+ response->result = reinterpret_cast<void *>(proxy);
+ response->isFinished = true;
+
+ //wake up waiting code
+ QTimer::singleShot(0, this, SIGNAL(pendingRequestFinished()));
+
+ } else {
+ //service side
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Service);
+
+ QServicePackage response = p.createResponse();
+ InstanceManager* m = InstanceManager::instance();
+
+ //get meta object from type register
+ const QMetaObject* meta = m->metaObject(p.d->entry);
+ if (!meta) {
+ qDebug() << "Unknown type" << p.d->entry;
+ dispatch->writePackage(response);
+ return;
+ }
+
+ //serialize meta object
+ QByteArray data;
+ QDataStream stream( &data, QIODevice::WriteOnly | QIODevice::Append );
+ QMetaObjectBuilder builder(meta);
+ builder.serialize(stream);
+
+ //instantiate service object from type register
+ service = m->createObjectInstance(p.d->entry, d->serviceInstanceId);
+ if (!service) {
+ qWarning() << "Cannot instanciate service object";
+ dispatch->writePackage(response);
+ return;
+ }
+ d->setupSignalIntercepters(service);
+
+ //send meta object
+ d->entry = p.d->entry;
+ response.d->entry = p.d->entry;
+ response.d->responseType = QServicePackage::Success;
+ response.d->payload = QVariant(data);
+ dispatch->writePackage(response);
+ }
+}
+
+void ObjectEndPoint::methodCall(const QServicePackage& p)
+{
+ if (p.d->responseType == QServicePackage::NotAResponse ) {
+ //service side if slot invocation
+ //client side if signal emission (isSignal==true)
+
+ QByteArray data = p.d->payload.toByteArray();
+ QDataStream stream(&data, QIODevice::ReadOnly);
+ int metaIndex = -1;
+ QVariantList args;
+ stream >> metaIndex;
+ stream >> args;
+
+ QMetaMethod method = service->metaObject()->method(metaIndex);
+ const bool isSignal = (method.methodType() == QMetaMethod::Signal);
+ const int returnType = QMetaType::type(method.typeName());
+
+ if (isSignal) {
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
+ // Construct the raw argument list.
+ /* we ignore a possible return type of the signal. The value is
+ not deterministic and it can actually create memory leaks
+ in moc generated code.
+ */
+ const int numArgs = args.size();
+ QVarLengthArray<void *, 32> a( numArgs+1 );
+ a[0] = 0;
+
+ const QList<QByteArray> pTypes = method.parameterTypes();
+ for ( int arg = 0; arg < numArgs; ++arg ) {
+ if (pTypes.at(arg) == "QVariant")
+ a[arg+1] = (void *)&( args[arg] );
+ else
+ a[arg+1] = (void *)( args[arg].data() );
+ }
+
+ d->triggerConnectedSlots(service, service->metaObject(), metaIndex, a.data());
+ return;
+ }
+ //service side
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Service);
+
+ const char* typenames[] = {0,0,0,0,0,0,0,0,0,0};
+ const void* param[] = {0,0,0,0,0,0,0,0,0,0};
+
+ for (int i=0; i<args.size(); i++) {
+ if (args[i].isValid()) {
+ typenames[i] = args[i].typeName();
+ } else {
+ if (method.parameterTypes().at(i) == "QVariant")
+ typenames[i] = "QVariant";
+ }
+ param[i] = args[i].constData();
+ }
+
+
+ bool result = false;
+ if (returnType == QMetaType::Void && strcmp(method.typeName(), "QVariant")) {
+ result = method.invoke(service,
+ QGenericArgument(typenames[0], param[0]),
+ QGenericArgument(typenames[1], param[1]),
+ QGenericArgument(typenames[2], param[2]),
+ QGenericArgument(typenames[3], param[3]),
+ QGenericArgument(typenames[4], param[4]),
+ QGenericArgument(typenames[5], param[5]),
+ QGenericArgument(typenames[6], param[6]),
+ QGenericArgument(typenames[7], param[7]),
+ QGenericArgument(typenames[8], param[8]),
+ QGenericArgument(typenames[9], param[9]));
+ } else {
+ //result buffer
+ QVariant returnValue;
+ //ignore whether QVariant is a declared meta type or not
+ if (returnType != QVariant::Invalid && strcmp(method.typeName(), "QVariant")) {
+ returnValue = QVariant(returnType, (const void*) 0);
+ }
+
+ QGenericReturnArgument ret(method.typeName(), returnValue.data());
+ result = method.invoke(service, ret,
+ QGenericArgument(typenames[0], param[0]),
+ QGenericArgument(typenames[1], param[1]),
+ QGenericArgument(typenames[2], param[2]),
+ QGenericArgument(typenames[3], param[3]),
+ QGenericArgument(typenames[4], param[4]),
+ QGenericArgument(typenames[5], param[5]),
+ QGenericArgument(typenames[6], param[6]),
+ QGenericArgument(typenames[7], param[7]),
+ QGenericArgument(typenames[8], param[8]),
+ QGenericArgument(typenames[9], param[9]));
+
+ QServicePackage response = p.createResponse();
+
+ if (result) {
+ response.d->responseType = QServicePackage::Success;
+ response.d->payload = returnValue;
+ } else {
+ response.d->responseType = QServicePackage::Failed;
+ }
+ dispatch->writePackage(response);
+
+ }
+ if (!result)
+ qWarning( "%s::%s cannot be called.", service->metaObject()->className(), method.signature());
+ } else {
+ //client side
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
+
+ Response* response = openRequests()->value(p.d->messageId);
+ if (response){
+ response->isFinished = true;
+ if (p.d->responseType == QServicePackage::Failed) {
+ response->result = 0;
+ QTimer::singleShot(0, this, SIGNAL(pendingRequestFinished()));
+ return;
+ }
+ QVariant* variant = new QVariant(p.d->payload);
+ response->result = reinterpret_cast<void *>(variant);
+
+ QTimer::singleShot(0, this, SIGNAL(pendingRequestFinished()));
+ }
+ }
+}
+
+/*
+ Will block if return value expected
+ Handles property calls
+*/
+QVariant ObjectEndPoint::invokeRemoteProperty(int metaIndex, const QVariant& arg, int /*returnType*/, QMetaObject::Call c )
+{
+ //client and service side
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Client
+ || d->endPointType == ObjectEndPoint::Service);
+
+ QServicePackage p;
+ p.d = new QServicePackagePrivate();
+ p.d->packageType = QServicePackage::PropertyCall;
+ p.d->messageId = QUuid::createUuid();
+
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly|QIODevice::Append);
+ stream << metaIndex << arg << c;
+ p.d->payload = data;
+
+ if (c == QMetaObject::ReadProperty) {
+ //create response and block for answer
+ Response* response = new Response();
+ openRequests()->insert(p.d->messageId, response);
+
+ dispatch->writePackage(p);
+ waitForResponse(p.d->messageId);
+
+ QVariant result;
+ if (response->isFinished) {
+ if (response->result == 0) {
+ qWarning() << "Service property call failed";
+ } else {
+ QVariant* resultPointer = reinterpret_cast<QVariant* >(response->result);
+ result = (*resultPointer);
+ delete resultPointer;
+ }
+ } else {
+ qDebug() << "response passed but not finished";
+ }
+
+ openRequests()->take(p.d->messageId);
+ delete response;
+
+ return result;
+ } else {
+ dispatch->writePackage(p);
+ }
+
+ return QVariant();
+}
+
+/*
+ Will block if return value expected
+ Handles signal/slots
+*/
+QVariant ObjectEndPoint::invokeRemote(int metaIndex, const QVariantList& args, int returnType)
+{
+ //client side
+ //Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
+
+ QServicePackage p;
+ p.d = new QServicePackagePrivate();
+ p.d->packageType = QServicePackage::MethodCall;
+ p.d->messageId = QUuid::createUuid();
+
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly|QIODevice::Append);
+ stream << metaIndex << args;
+ p.d->payload = data;
+
+ if (returnType == QMetaType::Void) {
+ dispatch->writePackage(p);
+ } else {
+ //create response and block for answer
+ Response* response = new Response();
+ openRequests()->insert(p.d->messageId, response);
+
+ dispatch->writePackage(p);
+ waitForResponse(p.d->messageId);
+
+ QVariant result;
+ if (response->isFinished) {
+ if (response->result == 0) {
+ qWarning() << "Remote function call failed";
+ } else {
+ QVariant* resultPointer = reinterpret_cast<QVariant* >(response->result);
+ result = (*resultPointer);
+ delete resultPointer;
+ }
+ } else {
+ qDebug() << "response passed but not finished";
+ }
+
+ openRequests()->take(p.d->messageId);
+ delete response;
+
+ return result;
+
+ }
+
+ return QVariant();
+}
+
+void ObjectEndPoint::waitForResponse(const QUuid& requestId)
+{
+ qDebug() << "start ObjectEndPoint::waitForResponse";
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
+ if (openRequests()->contains(requestId) ) {
+ Response* response = openRequests()->value(requestId);
+ QEventLoop* loop = new QEventLoop( this );
+ QTimer::singleShot(30000, loop, SLOT(quit()));
+ connect(this, SIGNAL(pendingRequestFinished()), loop, SLOT(quit()));
+ loop->exec();
+ delete loop;
+ qDebug() << "- response->isFinished: " << response->isFinished;
+
+ }
+ qDebug() << "finished ObjectEndPoint::waitForResponse";
+}
+
+#include "moc_objectendpoint_p.cpp"
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/objectendpoint_dbus.cpp b/src/serviceframework/ipc/objectendpoint_dbus.cpp
new file mode 100644
index 00000000..ce03e864
--- /dev/null
+++ b/src/serviceframework/ipc/objectendpoint_dbus.cpp
@@ -0,0 +1,728 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "objectendpoint_dbus_p.h"
+#include "instancemanager_p.h"
+#include "qmetaobjectbuilder_p.h"
+#include "proxyobject_p.h"
+#include "qsignalintercepter_p.h"
+#include <QTimer>
+#include <QEventLoop>
+#include <QVarLengthArray>
+
+QTM_BEGIN_NAMESPACE
+
+class Response
+{
+public:
+ Response() : isFinished(false), result(0)
+ { }
+
+ bool isFinished;
+ void* result;
+};
+
+typedef QHash<QUuid, Response*> Replies;
+Q_GLOBAL_STATIC(Replies, openRequests);
+
+class ServiceSignalIntercepter : public QSignalIntercepter
+{
+ //Do not put Q_OBJECT here
+public:
+ ServiceSignalIntercepter(QObject* sender, const QByteArray& signal,
+ ObjectEndPoint* parent)
+ : QSignalIntercepter(sender, signal, parent), endPoint(parent)
+ {
+
+ }
+
+ void setMetaIndex(int index)
+ {
+ metaIndex = index;
+ }
+
+protected:
+ void activated( const QList<QVariant>& args )
+ {
+ endPoint->invokeRemote(metaIndex, args, QMetaType::Void);
+ }
+private:
+ ObjectEndPoint* endPoint;
+ int metaIndex;
+};
+
+struct ClientInstance {
+ QString clientId;
+ QRemoteServiceRegister::Entry entry;
+ QUuid instanceId;
+ int ref;
+};
+
+class ObjectEndPointPrivate
+{
+public:
+ ObjectEndPointPrivate()
+ {
+ }
+
+ ~ObjectEndPointPrivate()
+ {
+ }
+
+ // Used on client and service side
+ ObjectEndPoint::Type endPointType;
+ ObjectEndPoint* parent;
+
+ // Used to calculate the registered paths on DBus
+ QRemoteServiceRegister::Entry entry;
+ QUuid serviceInstanceId;
+
+ // Service side local client ownership list
+ QList<ClientInstance> clientList;
+};
+
+/*!
+ Client to service communication only used for establishing an object request since the returned
+ proxy is an interface to that object registered on QtDBus. Client communicates directly to QtDBus
+ for method and property access. Signals are automatically relayed from QtDBus to the proxy object.
+*/
+ObjectEndPoint::ObjectEndPoint(Type type, QServiceIpcEndPoint* comm, QObject* parent)
+ : QObject(parent), dispatch(comm), service(0), iface(0)
+{
+ Q_ASSERT(dispatch);
+ d = new ObjectEndPointPrivate;
+ d->parent = this;
+ d->endPointType = type;
+
+ dispatch->setParent(this);
+ connect(dispatch, SIGNAL(readyRead()), this, SLOT(newPackageReady()));
+ if (type == Client) {
+ // client waiting for construct proxy and registers DBus custom type
+ qDBusRegisterMetaType<QTM_PREPEND_NAMESPACE(QServiceUserTypeDBus)>();
+ qRegisterMetaType<QTM_PREPEND_NAMESPACE(QServiceUserTypeDBus)>();
+ return;
+ } else {
+ connect(InstanceManager::instance(),
+ SIGNAL(instanceClosed(QRemoteServiceRegister::Entry,QUuid)),
+ this, SLOT(unregisterObjectDBus(QRemoteServiceRegister::Entry,QUuid)));
+
+ if (dispatch->packageAvailable())
+ QTimer::singleShot(0, this, SLOT(newPackageReady()));
+ }
+}
+
+ObjectEndPoint::~ObjectEndPoint()
+{
+ if (iface)
+ delete iface;
+ delete d;
+}
+
+/*!
+ Removes all instances of the client from the instance manager
+*/
+void ObjectEndPoint::disconnected(const QString& clientId, const QString& instanceId)
+{
+ // Service Side
+ Q_ASSERT(d->endPointType != ObjectEndPoint::Client);
+
+ for (int i=d->clientList.size()-1; i>=0; i--) {
+ // Find right client process
+ if (d->clientList[i].clientId == clientId) {
+ if (d->clientList[i].ref-- == 1) {
+ QRemoteServiceRegister::Entry entry = d->clientList[i].entry;
+ QUuid instance = d->clientList[i].instanceId;
+
+ if (instance.toString() == instanceId) {
+ // Remove an instance from the InstanceManager and local list
+ InstanceManager::instance()->removeObjectInstance(entry, instance);
+ d->clientList.removeAt(i);
+ }
+ }
+ }
+ }
+}
+
+/*!
+ Unregisters the DBus object
+*/
+void ObjectEndPoint::unregisterObjectDBus(const QRemoteServiceRegister::Entry& entry, const QUuid& id)
+{
+ uint hash = qHash(id.toString());
+ QString objPath = "/" + entry.interfaceName() + "/" + entry.version() +
+ "/" + QString::number(hash);
+ objPath.replace(QLatin1String("."), QLatin1String("/"));
+ QDBusConnection::sessionBus().unregisterObject(objPath, QDBusConnection::UnregisterTree);
+}
+
+/*!
+ Client requests proxy object. The proxy is owned by calling
+ code and this object must clean itself up upon destruction of
+ proxy.
+*/
+QObject* ObjectEndPoint::constructProxy(const QRemoteServiceRegister::Entry& entry)
+{
+ // Client side
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
+
+ // Request a serialized meta object
+ QServicePackage p;
+ p.d = new QServicePackagePrivate();
+ p.d->messageId = QUuid::createUuid();
+ p.d->entry = entry;
+
+ Response* response = new Response();
+ openRequests()->insert(p.d->messageId, response);
+
+ dispatch->writePackage(p);
+ waitForResponse(p.d->messageId);
+
+ // Get the proxy based on the meta object
+ if (response->isFinished) {
+ if (response->result == 0)
+ qWarning() << "Request for remote service failed";
+ else
+ service = reinterpret_cast<QServiceProxy* >(response->result);
+ } else {
+ qDebug() << "response passed but not finished";
+ }
+
+ openRequests()->take(p.d->messageId);
+ delete response;
+
+ if (!service)
+ return 0;
+
+ // Connect all DBus interface signals to the proxy slots
+ const QMetaObject *mo = service->metaObject();
+ while (mo && strcmp(mo->className(), "QObject")) {
+ for (int i = mo->methodOffset(); i < mo->methodCount(); i++) {
+ const QMetaMethod mm = mo->method(i);
+ if (mm.methodType() == QMetaMethod::Signal) {
+ QByteArray sig(mm.signature());
+
+ bool customType = false;
+
+ QList<QByteArray> params = mm.parameterTypes();
+ for (int arg = 0; arg < params.size(); arg++) {
+ const QByteArray& type = params[arg];
+ int variantType = QVariant::nameToType(type);
+ if (variantType == QVariant::UserType) {
+ sig.replace(QByteArray(type), QByteArray("QDBusVariant"));
+ customType = true;
+ }
+ }
+
+ int serviceIndex = iface->metaObject()->indexOfSignal(sig);
+ QByteArray signal = QByteArray("2").append(sig);
+
+ if (serviceIndex > 0) {
+ if (customType) {
+ QObject::connect(iface, signal.constData(), signalsObject, signal.constData());
+
+ ServiceSignalIntercepter *intercept =
+ new ServiceSignalIntercepter((QObject*)signalsObject, signal, this);
+ intercept->setMetaIndex(i);
+ } else {
+ QObject::connect(iface, signal.constData(), service, signal.constData());
+ }
+ }
+ }
+ }
+ mo = mo->superClass();
+ }
+
+ return service;
+}
+
+/*!
+ Received a new package from the DBus client-server controller.
+ Once an object request is handled there is only direct communication to the DBus object so
+ no other package types should be received on this layer.
+*/
+void ObjectEndPoint::newPackageReady()
+{
+ // Client and service side
+ while (dispatch->packageAvailable())
+ {
+ QServicePackage p = dispatch->nextPackage();
+ if (!p.isValid())
+ continue;
+
+ if (p.d->packageType == QServicePackage::ObjectCreation) {
+ objectRequest(p);
+ } else {
+ qWarning() << "Unknown package type received.";
+ }
+ }
+}
+
+/*!
+ Service finds existing objects or spawns new object instances and registers them on DBus using a
+ hash of the unique instance ID. This registered object has a special metaobject representation
+ of the service that is compatible with the QDBus type system.
+
+ Client receives a package containing the information to connect an interface to the registered
+ DBus object.
+*/
+void ObjectEndPoint::objectRequest(const QServicePackage& p)
+{
+ if (p.d->responseType != QServicePackage::NotAResponse ) {
+ // Client side
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
+
+ d->serviceInstanceId = p.d->instanceId;
+ d->entry = p.d->entry;
+
+ Response* response = openRequests()->value(p.d->messageId);
+ if (p.d->responseType == QServicePackage::Failed) {
+ response->result = 0;
+ response->isFinished = true;
+ QTimer::singleShot(0, this, SIGNAL(pendingRequestFinished()));
+ qWarning() << "Service instantiation failed";
+ return;
+ }
+
+ // Deserialize meta object and create proxy object
+ QServiceProxy* proxy = new QServiceProxy(p.d->payload.toByteArray(), this);
+ response->result = reinterpret_cast<void *>(proxy);
+ response->isFinished = true;
+
+ // Create DBUS interface by using a hash of the service instance ID
+ QString serviceName = "com.nokia.qtmobility.sfw." + p.d->entry.serviceName();
+ uint hash = qHash(d->serviceInstanceId.toString());
+ QString objPath = "/" + p.d->entry.interfaceName() + "/" + p.d->entry.version() + "/" + QString::number(hash);
+ objPath.replace(QLatin1String("."), QLatin1String("/"));
+
+#ifdef DEBUG
+ qDebug() << "Client Interface ObjectPath:" << objPath;
+#endif
+ // Instantiate our DBus interface and its corresponding signals object
+ if (!iface)
+ iface = new QDBusInterface(serviceName, objPath, QLatin1String(""), QDBusConnection::sessionBus(), this);
+ signalsObject = new QServiceMetaObjectDBus(iface, true);
+
+ // Wake up waiting proxy construction code
+ QTimer::singleShot(0, this, SIGNAL(pendingRequestFinished()));
+
+ } else {
+ // Service side
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Service);
+
+ QServicePackage response = p.createResponse();
+ InstanceManager* iManager = InstanceManager::instance();
+
+ // Instantiate service object from type register
+ service = iManager->createObjectInstance(p.d->entry, d->serviceInstanceId);
+ if (!service) {
+ qWarning() << "Cannot instantiate service object";
+ dispatch->writePackage(response);
+ return;
+ }
+
+ // Start DBus connection and register proxy service
+ if (!QDBusConnection::sessionBus().isConnected()) {
+ qWarning() << "Cannot connect to DBus";
+ }
+
+ // DBus registration path uses a hash of the service instance ID
+ QString serviceName = "com.nokia.qtmobility.sfw." + p.d->entry.serviceName();
+ uint hash = qHash(d->serviceInstanceId.toString());
+ QString objPath = "/" + p.d->entry.interfaceName() + "/" + p.d->entry.version() + "/" + QString::number(hash);
+ objPath.replace(QLatin1String("."), QLatin1String("/"));
+
+ QServiceMetaObjectDBus *serviceDBus = new QServiceMetaObjectDBus(service);
+ QDBusConnection::sessionBus().registerObject(objPath, serviceDBus, QDBusConnection::ExportAllContents);
+
+ QString clientId = p.d->payload.toString();
+
+ int exists = 0;
+ for (int i=d->clientList.size()-1; i>=0; i--) {
+ // Find right client process
+ if (d->clientList[i].clientId == clientId) {
+ d->clientList[i].ref++;
+ exists = 1;
+ break;
+ }
+ }
+
+ if (!exists) {
+ // Add new instance to client ownership list
+ ClientInstance c;
+ c.clientId = clientId;
+ c.entry = p.d->entry;
+ c.instanceId = d->serviceInstanceId;
+ c.ref = 1;
+ d->clientList << c;
+ }
+
+
+
+#ifdef DEBUG
+ qDebug() << "Service Interface ObjectPath:" << objPath;
+
+ const QMetaObject *s_meta = service->metaObject();
+ qDebug() << "+++++++++++++++++++++SERVICE+++++++++++++++++++++++";
+ qDebug() << s_meta->className();
+ qDebug() << "METHOD COUNT: " << s_meta->methodCount();
+ for (int i=0; i<s_meta->methodCount(); i++) {
+ QMetaMethod mm = s_meta->method(i);
+
+ QString type;
+ switch (mm.methodType()) {
+ case QMetaMethod::Method:
+ type = "Q_INVOKABLE";
+ break;
+ case QMetaMethod::Signal:
+ type = "SIGNAL";
+ break;
+ case QMetaMethod::Slot:
+ type = "SLOT";
+ break;
+ default:
+ break;
+ }
+
+ QString returnType = mm.typeName();
+ if (returnType == "") returnType = "void";
+
+ qDebug() << "METHOD" << type << ":" << returnType << mm.signature();
+ }
+ qDebug() << "++++++++++++++++++++++++++++++++++++++++++++++++++++";
+ if (!iface)
+ iface = new QDBusInterface(serviceName, objPath, "", QDBusConnection::sessionBus(), this);
+ const QMetaObject *i_meta = iface->metaObject();
+ qDebug() << "++++++++++++++++++++DBUS SERVICE++++++++++++++++++++";
+ qDebug() << i_meta->className();
+ qDebug() << "METHOD COUNT: " << i_meta->methodCount();
+ for (int i=0; i<i_meta->methodCount(); i++) {
+ QMetaMethod mm = i_meta->method(i);
+
+ QString type;
+ switch (mm.methodType()) {
+ case QMetaMethod::Method:
+ type = "Q_INVOKABLE";
+ break;
+ case QMetaMethod::Signal:
+ type = "SIGNAL";
+ break;
+ case QMetaMethod::Slot:
+ type = "SLOT";
+ break;
+ default:
+ break;
+ }
+
+ QString returnType = mm.typeName();
+ if (returnType == "") returnType = "void";
+
+ qDebug() << "METHOD" << type << ":" << returnType << mm.signature();
+ }
+ qDebug() << "+++++++++++++++++++++++++++++++++++++++++++++++++++";
+#endif
+
+ // Get meta object from type register
+ const QMetaObject* meta = iManager->metaObject(p.d->entry);
+ if (!meta) {
+ qDebug() << "Unknown type" << p.d->entry;
+ dispatch->writePackage(response);
+ return;
+ }
+
+ // Serialize meta object
+ QByteArray data;
+ QDataStream stream( &data, QIODevice::WriteOnly | QIODevice::Append );
+ QMetaObjectBuilder builder(meta);
+ builder.serialize(stream);
+
+ // Send meta object and instance ID to the client for processing
+ d->entry = p.d->entry;
+ response.d->instanceId = d->serviceInstanceId;
+ response.d->entry = p.d->entry;
+ response.d->responseType = QServicePackage::Success;
+ response.d->payload = QVariant(data);
+ dispatch->writePackage(response);
+ }
+}
+
+/*!
+ Returns the created service instance Id
+*/
+QString ObjectEndPoint::getInstanceId() const
+{
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
+
+ return d->serviceInstanceId.toString();
+}
+
+/*!
+ Client side property call that directly accesses properties through the DBus interface.
+ Read and reset have special hardcoded DBus methods due to the nature of QtDBus properties
+ without an adaptor class incorrectly forwarding the metacall type
+*/
+QVariant ObjectEndPoint::invokeRemoteProperty(int metaIndex, const QVariant& arg, int /*returnType*/, QMetaObject::Call c )
+{
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
+
+ const QMetaObject *imeta = service->metaObject();
+ QMetaProperty property = imeta->property(metaIndex);
+
+ if (c == QMetaObject::WriteProperty) {
+ // Writing property, direct property DBus call
+ if (!iface->setProperty(property.name(), arg)) {
+ qWarning() << "Service property write call failed";
+ }
+
+ } else if (c == QMetaObject::ResetProperty) {
+ // Resetting property, direct special method DBus call
+ QVariantList args;
+ args << QVariant(QLatin1String(property.name()));
+ QDBusMessage msg = iface->callWithArgumentList(QDBus::Block, QLatin1String("propertyReset"), args);
+ if (msg.type() == QDBusMessage::InvalidMessage) {
+ qWarning() << "Service property reset call failed";
+ }
+
+ } else if (c == QMetaObject::ReadProperty) {
+ // Reading property, direct special method DBus call
+ QVariantList args;
+ args << QVariant(QLatin1String(property.name()));
+ QDBusMessage msg = iface->callWithArgumentList(QDBus::Block, QLatin1String("propertyRead"), args);
+ if (msg.type() == QDBusMessage::ReplyMessage) {
+ QVariantList retList = msg.arguments();
+ return retList[0];
+ } else {
+ qWarning() << "Service property read call failed" << msg.errorMessage();
+ }
+ } else {
+ qWarning() << "Invalid property call";
+ }
+
+ return QVariant();
+}
+
+/*!
+ Client side method call that converts an argument of type to its corresponding value as a
+ valid type supported by the QtDBus type system.
+
+ Supports conversion from a QVariant, QList, QMap, QHash, and custom user-defined types.
+*/
+QVariant ObjectEndPoint::toDBusVariant(const QByteArray& type, const QVariant& arg)
+{
+ QVariant dbusVariant = arg;
+
+ int variantType = QVariant::nameToType(type);
+ if (variantType == QVariant::UserType) {
+ variantType = QMetaType::type(type);
+
+ if (type == "QVariant") {
+ // Wrap QVariants in a QDBusVariant
+ QDBusVariant replacement(arg);
+ dbusVariant = QVariant::fromValue(replacement);
+ } else {
+ // Wrap custom types in a QDBusVariant of the type name and
+ // a buffer of its variant-wrapped data
+ QByteArray buffer;
+ QDataStream stream(&buffer, QIODevice::ReadWrite | QIODevice::Append);
+ stream << arg;
+
+ QServiceUserTypeDBus customType;
+ customType.typeName = type;
+ customType.variantBuffer = buffer;
+
+ QDBusVariant replacement(QVariant::fromValue(customType));
+ dbusVariant = QVariant::fromValue(replacement);
+ }
+ }
+
+ return dbusVariant;
+}
+
+/*!
+ Client side method call that directly accesses the object through the DBus interface.
+ All arguments and return types are processed and converted accordingly so that all functions
+ satisfy the QtDBus type system.
+*/
+QVariant ObjectEndPoint::invokeRemote(int metaIndex, const QVariantList& args, int returnType)
+{
+ QMetaMethod method = service->metaObject()->method(metaIndex);
+
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
+
+ // Check is this is a signal relay
+ if (method.methodType() == QMetaMethod::Signal) {
+ // Convert custom arguments
+ QVariantList convertedList;
+ QList<QByteArray> params = method.parameterTypes();
+ for (int i = 0; i < params.size(); i++) {
+ const QByteArray& type = params[i];
+ int variantType = QVariant::nameToType(type);
+ if (variantType == QVariant::UserType) {
+ variantType = QMetaType::type(type);
+
+ QDBusVariant dbusVariant = qvariant_cast<QDBusVariant>(args[i]);
+ QVariant variant = dbusVariant.variant();
+
+ if (type == "QVariant") {
+ convertedList << variant;
+ } else {
+ QByteArray buffer = variant.toByteArray();
+ QDataStream stream(&buffer, QIODevice::ReadWrite);
+ QVariant *customType = new QVariant(variantType, (const void*)0);
+ QMetaType::load(stream, QMetaType::type("QVariant"), customType);
+ convertedList << *customType;
+ }
+ } else {
+ convertedList << args[i];
+ }
+ }
+
+ // Signal relay
+ const int numArgs = convertedList.size();
+ QVarLengthArray<void *, 32> a( numArgs+1 );
+ a[0] = 0;
+
+ const QList<QByteArray> pTypes = method.parameterTypes();
+ for ( int arg = 0; arg < numArgs; ++arg ) {
+ if (pTypes.at(arg) == "QVariant") {
+ a[arg+1] = (void *)&( convertedList[arg] );
+ } else {
+ a[arg+1] = (void *)( convertedList[arg].data() );
+ }
+ }
+
+ // Activate the service proxy signal call
+ QMetaObject::activate(service, metaIndex, a.data());
+ return QVariant();
+ }
+
+ // Method call so process arguments and convert if not a supported DBus type
+ QVariantList convertedList;
+ QList<QByteArray> params = method.parameterTypes();
+ for (int i = 0; i < params.size(); i++) {
+ QVariant converted = toDBusVariant(params[i], args[i]);
+ convertedList << converted;
+ }
+
+ bool validDBus = false;
+ QDBusMessage msg;
+
+ // Find the method name and try a direct DBus call
+ QString methodName(QLatin1String(method.signature()));
+ methodName.truncate(methodName.indexOf(QLatin1String("(")));
+
+ if (method.methodType() == QMetaMethod::Slot || method.methodType() == QMetaMethod::Method) {
+ // Slot or Invokable method
+ msg = iface->callWithArgumentList(QDBus::Block, methodName, convertedList);
+ if (msg.type() == QDBusMessage::ReplyMessage) {
+ validDBus = true;
+ }
+ }
+
+ // DBus call should only fail for methods with invalid type definitions
+ if (validDBus) {
+ if (returnType == QMetaType::Void) {
+ // Void method call
+ return QVariant();
+ }
+ else {
+ // Use DBus message return value
+ QVariantList retList = msg.arguments();
+
+ // Process return
+ const QByteArray& retType = QByteArray(method.typeName());
+ int variantType = QVariant::nameToType(retType);
+ if (variantType == QVariant::UserType) {
+ variantType = QMetaType::type(retType);
+
+ if (retType == "QVariant") {
+ // QVariant return from QDBusVariant wrapper
+ QDBusVariant dbusVariant = qvariant_cast<QDBusVariant>(retList[0]);
+ return dbusVariant.variant();
+ } else {
+ // Custom return type
+ QDBusVariant dbusVariant = qvariant_cast<QDBusVariant>(retList[0]);
+ QVariant convert = dbusVariant.variant();
+
+ QServiceUserTypeDBus customType = qdbus_cast<QServiceUserTypeDBus>(convert);
+ QByteArray buffer = customType.variantBuffer;
+ QDataStream stream(&buffer, QIODevice::ReadWrite);
+
+ // Load our buffered variant-wrapped custom return
+ QVariant *customReturn = new QVariant(variantType, (const void*)0);
+ QMetaType::load(stream, QMetaType::type("QVariant"), customReturn);
+
+ return QVariant(variantType, customReturn->data());
+ }
+ } else {
+ // Standard return type
+ return retList[0];
+ }
+ }
+ } else {
+ qWarning( "%s::%s cannot be called.", service->metaObject()->className(), method.signature());
+ }
+
+ return QVariant();
+}
+
+/*!
+ Client side waits for service side requested
+*/
+void ObjectEndPoint::waitForResponse(const QUuid& requestId)
+{
+ Q_ASSERT(d->endPointType == ObjectEndPoint::Client);
+
+ if (openRequests()->contains(requestId) ) {
+ Response* response = openRequests()->value(requestId);
+ QEventLoop* loop = new QEventLoop( this );
+ connect(this, SIGNAL(pendingRequestFinished()), loop, SLOT(quit()));
+
+ while(!response->isFinished) {
+ loop->exec();
+ }
+
+ delete loop;
+ }
+}
+
+#include "moc_objectendpoint_dbus_p.cpp"
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/objectendpoint_dbus_p.h b/src/serviceframework/ipc/objectendpoint_dbus_p.h
new file mode 100644
index 00000000..a8d3133f
--- /dev/null
+++ b/src/serviceframework/ipc/objectendpoint_dbus_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OBJECT_ENDPOINT_DBUS_H
+#define OBJECT_ENDPOINT_DBUS_H
+
+#include "qserviceframeworkglobal.h"
+#include "ipcendpoint_p.h"
+#include "qremoteserviceregister.h"
+#include "qservice.h"
+#include <QPointer>
+#include <QHash>
+#include <QtDBus>
+#include "qservicemetaobject_dbus_p.h"
+
+QTM_BEGIN_NAMESPACE
+
+class QServiceMetaObjectDBus;
+class ObjectEndPointPrivate;
+class ObjectEndPoint : public QObject
+{
+ Q_OBJECT
+public:
+ enum Type {
+ Service = 0,
+ Client
+ };
+
+ ObjectEndPoint(Type type, QServiceIpcEndPoint* comm, QObject* parent = 0);
+ ~ObjectEndPoint();
+
+ QObject* constructProxy(const QRemoteServiceRegister::Entry& entry);
+
+ void objectRequest(const QServicePackage& p);
+ void methodCall(const QServicePackage& p);
+ void propertyCall(const QServicePackage& p);
+
+ QString getInstanceId() const;
+
+ QVariant invokeRemote(int metaIndex, const QVariantList& args, int returnType);
+ QVariant invokeRemoteProperty(int metaIndex, const QVariant& arg, int returnType, QMetaObject::Call c);
+
+Q_SIGNALS:
+ void pendingRequestFinished();
+
+public Q_SLOTS:
+ void newPackageReady();
+ void disconnected(const QString& clientId, const QString & instanceId);
+ void unregisterObjectDBus(const QRemoteServiceRegister::Entry& entry, const QUuid& id);
+
+private:
+ void waitForResponse(const QUuid& requestId);
+ QVariant toDBusVariant(const QByteArray& type, const QVariant& arg);
+
+ QServiceIpcEndPoint* dispatch;
+ QPointer<QObject> service;
+ ObjectEndPointPrivate* d;
+
+ QDBusInterface *iface;
+ QServiceMetaObjectDBus *signalsObject;
+};
+
+QTM_END_NAMESPACE
+
+#endif //OBJECT_ENDPOINT_DBUS_H
diff --git a/src/serviceframework/ipc/objectendpoint_p.h b/src/serviceframework/ipc/objectendpoint_p.h
new file mode 100644
index 00000000..7cd67e20
--- /dev/null
+++ b/src/serviceframework/ipc/objectendpoint_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef OBJECT_ENDPOINT_H
+#define OBJECT_ENDPOINT_H
+
+#include "qserviceframeworkglobal.h"
+#include "ipcendpoint_p.h"
+#include "qremoteserviceregister.h"
+#include "qservice.h"
+#include <QPointer>
+#include <QHash>
+
+QTM_BEGIN_NAMESPACE
+
+class ObjectEndPointPrivate;
+class ObjectEndPoint : public QObject
+{
+ Q_OBJECT
+public:
+ enum Type {
+ Service = 0,
+ Client
+ };
+
+ ObjectEndPoint(Type type, QServiceIpcEndPoint* comm, QObject* parent = 0);
+ ~ObjectEndPoint();
+ QObject* constructProxy(const QRemoteServiceRegister::Entry& entry);
+
+ void objectRequest(const QServicePackage& p);
+ void methodCall(const QServicePackage& p);
+ void propertyCall(const QServicePackage& p);
+
+ QVariant invokeRemote(int metaIndex, const QVariantList& args, int returnType);
+ QVariant invokeRemoteProperty(int metaIndex, const QVariant& arg, int returnType, QMetaObject::Call c);
+
+Q_SIGNALS:
+ void pendingRequestFinished();
+
+public Q_SLOTS:
+ void newPackageReady();
+ void disconnected();
+
+private:
+ void waitForResponse(const QUuid& requestId);
+
+ QServiceIpcEndPoint* dispatch;
+ QPointer<QObject> service;
+ ObjectEndPointPrivate* d;
+};
+
+QTM_END_NAMESPACE
+
+#endif //OBJECT_ENDPOINT_H
diff --git a/src/serviceframework/ipc/proxyobject.cpp b/src/serviceframework/ipc/proxyobject.cpp
new file mode 100644
index 00000000..4ba5179f
--- /dev/null
+++ b/src/serviceframework/ipc/proxyobject.cpp
@@ -0,0 +1,227 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "proxyobject_p.h"
+#include "qmetaobjectbuilder_p.h"
+#include "qremoteserviceregisterentry_p.h"
+
+#include <QDebug>
+
+QTM_BEGIN_NAMESPACE
+
+class QServiceProxyPrivate
+{
+public:
+ QByteArray metadata;
+ QMetaObject* meta;
+ ObjectEndPoint* endPoint;
+};
+
+QServiceProxy::QServiceProxy(const QByteArray& metadata, ObjectEndPoint* endPoint, QObject* parent)
+ : QObject(parent)
+{
+ Q_ASSERT(endPoint);
+ d = new QServiceProxyPrivate();
+ d->metadata = metadata;
+ d->meta = 0;
+ d->endPoint = endPoint;
+
+ QDataStream stream(d->metadata);
+ QMetaObjectBuilder builder;
+ QMap<QByteArray, const QMetaObject*> refs;
+
+ builder.deserialize(stream, refs);
+ if (stream.status() != QDataStream::Ok) {
+ qWarning() << "Invalid metaObject for service received";
+ } else {
+ QMetaMethodBuilder b = builder.addSignal("errorUnrecoverableIPCFault(QService::UnrecoverableIPCError)");
+
+ // After all methods are filled in, otherwise qvector won't be big enough
+ localSignals.fill(false, builder.methodCount());
+ localSignals.replace(b.index(), true); // Call activate locally
+
+ d->meta = builder.toMetaObject();
+ }
+}
+
+QServiceProxy::~QServiceProxy()
+{
+ if (d->meta)
+ qFree(d->meta);
+ delete d;
+}
+
+//provide custom Q_OBJECT implementation
+const QMetaObject* QServiceProxy::metaObject() const
+{
+ return d->meta;
+}
+
+int QServiceProxy::qt_metacall(QMetaObject::Call c, int id, void **a)
+{
+ id = QObject::qt_metacall(c, id, a);
+ if (id < 0 || !d->meta)
+ return id;
+
+ if (localSignals.at(id)){
+ QMetaObject::activate(this, d->meta, id, a);
+ return id;
+ }
+
+ if (c == QMetaObject::InvokeMetaMethod) {
+ const int mcount = d->meta->methodCount() - d->meta->methodOffset();
+ const int metaIndex = id + d->meta->methodOffset();
+
+ QMetaMethod method = d->meta->method(metaIndex);
+
+ const int returnType = QMetaType::type(method.typeName());
+
+ //process arguments
+ const QList<QByteArray> pTypes = method.parameterTypes();
+ const int pTypesCount = pTypes.count();
+ QVariantList args ;
+ if (pTypesCount > 10) {
+ qWarning() << "Cannot call" << method.signature() << ". More than 10 parameter.";
+ return id;
+ }
+ for (int i=0; i < pTypesCount; i++) {
+ const QByteArray& t = pTypes[i];
+
+ int variantType = QVariant::nameToType(t);
+ if (variantType == QVariant::UserType)
+ variantType = QMetaType::type(t);
+
+ if (t == "QVariant") { //ignore whether QVariant is declared as metatype
+ args << *reinterpret_cast<const QVariant(*)>(a[i+1]);
+ } else if ( variantType == 0 ){
+ qWarning("%s: argument %s has unknown type. Use qRegisterMetaType to register it.",
+ method.signature(), t.data());
+ return id;
+ } else {
+ args << QVariant(variantType, a[i+1]);
+ }
+ }
+
+ //QVariant looks the same as Void type. we need to distinguish them
+ if (returnType == QMetaType::Void && strcmp(method.typeName(),"QVariant") ) {
+ d->endPoint->invokeRemote(metaIndex, args, returnType);
+ } else {
+ //TODO: ugly but works
+ //add +1 if we have a variant return type to avoid triggering of void
+ //code path
+ //invokeRemote() parameter list needs review
+ QVariant result = d->endPoint->invokeRemote(metaIndex, args,
+ returnType==0 ? returnType+1: returnType);
+ if (result.type() != QVariant::Invalid){
+ if (returnType != 0 && strcmp(method.typeName(),"QVariant")) {
+ QByteArray buffer;
+ QDataStream stream(&buffer, QIODevice::ReadWrite);
+ QMetaType::save(stream, returnType, result.constData());
+ stream.device()->seek(0);
+ QMetaType::load(stream, returnType, a[0]);
+ } else {
+ if (a[0]) *reinterpret_cast< QVariant*>(a[0]) = result;
+ }
+ }
+ }
+ id-=mcount;
+ } else if ( c == QMetaObject::ReadProperty
+ || c == QMetaObject::WriteProperty
+ || c == QMetaObject::ResetProperty ) {
+ const int pCount = d->meta->propertyCount() - d->meta->propertyOffset();
+ const int metaIndex = id + d->meta->propertyOffset();
+ QMetaProperty property = d->meta->property(metaIndex);
+ if (property.isValid()) {
+ int pType = property.type();
+ if (pType == QVariant::UserType)
+ pType = QMetaType::type(property.typeName());
+
+ QVariant arg;
+ if ( c == QMetaObject::WriteProperty ) {
+ if (pType == QVariant::Invalid && QByteArray(property.typeName()) == "QVariant")
+ arg = *reinterpret_cast<const QVariant(*)>(a[0]);
+ else if (pType == 0) {
+ qWarning("%s: property %s has unkown type", property.name(), property.typeName());
+ return id;
+ } else {
+ arg = QVariant(pType, a[0]);
+ }
+ }
+ QVariant result;
+ if (c == QMetaObject::ReadProperty) {
+ result = d->endPoint->invokeRemoteProperty(metaIndex, arg, pType, c);
+ //wrap result for client
+ if (pType != 0) {
+ QByteArray buffer;
+ QDataStream stream(&buffer, QIODevice::ReadWrite);
+ QMetaType::save(stream, pType, result.constData());
+ stream.device()->seek(0);
+ QMetaType::load(stream, pType, a[0]);
+ } else {
+ if (a[0]) *reinterpret_cast< QVariant*>(a[0]) = result;
+ }
+ } else {
+ d->endPoint->invokeRemoteProperty(metaIndex, arg, pType, c);
+ }
+ }
+ id-=pCount;
+ } else if ( c == QMetaObject::QueryPropertyDesignable
+ || c == QMetaObject::QueryPropertyScriptable
+ || c == QMetaObject::QueryPropertyStored
+ || c == QMetaObject::QueryPropertyEditable
+ || c == QMetaObject::QueryPropertyUser )
+ {
+ //Nothing to do?
+ //These values are part of the transferred meta object already
+ } else {
+ //TODO
+ qWarning() << "MetaCall type" << c << "not yet handled";
+ }
+ return id;
+}
+
+void *QServiceProxy::qt_metacast(const char* className)
+{
+ if (!className) return 0;
+ //this object should not be castable to anything but QObject
+ return QObject::qt_metacast(className);
+}
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/proxyobject_p.h b/src/serviceframework/ipc/proxyobject_p.h
new file mode 100644
index 00000000..098a3b3a
--- /dev/null
+++ b/src/serviceframework/ipc/proxyobject_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROXY_OBJECT_H
+#define PROXY_OBJECT_H
+
+#include "qserviceframeworkglobal.h"
+
+#ifdef QT_NO_DBUS
+ #include "objectendpoint_p.h"
+#else
+ #include "objectendpoint_dbus_p.h"
+#endif
+
+#include <QObject>
+
+QTM_BEGIN_NAMESPACE
+
+class QServiceProxyPrivate;
+class QServiceProxy : public QObject
+{
+ //TODO make inherit from QRemoteService
+ //Note: Do not put Q_OBJECT here
+public:
+ QServiceProxy(const QByteArray& metadata, ObjectEndPoint* endpoint, QObject* parent = 0);
+ virtual ~QServiceProxy();
+
+ //provide custom Q_OBJECT implementation
+ virtual const QMetaObject* metaObject() const;
+ int qt_metacall(QMetaObject::Call c, int id, void **a);
+ void *qt_metacast(const char* className);
+
+private:
+ QServiceProxyPrivate* d;
+ QVector<bool> localSignals;
+};
+
+
+
+QTM_END_NAMESPACE
+
+#endif //PROXY_OBJECT_H
diff --git a/src/serviceframework/ipc/qmetaobjectbuilder.cpp b/src/serviceframework/ipc/qmetaobjectbuilder.cpp
new file mode 100644
index 00000000..acb98b81
--- /dev/null
+++ b/src/serviceframework/ipc/qmetaobjectbuilder.cpp
@@ -0,0 +1,2611 @@
+/****************************************************************************
+**
+** 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 QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmetaobjectbuilder_p.h"
+#include <QDebug>
+
+#ifndef Q_OS_WIN
+#include <stdint.h>
+#endif
+
+QTM_BEGIN_NAMESPACE
+
+/*!
+ \class QMetaObjectBuilder
+ \internal
+ \brief The QMetaObjectBuilder class supports building QMetaObject objects at runtime.
+ \since 1.1
+
+*/
+
+/*!
+ \enum QMetaObjectBuilder::AddMember
+ This enum defines which members of QMetaObject should be copied by QMetaObjectBuilder::addMetaObject()
+
+ \value ClassName Add the class name.
+ \value SuperClass Add the super class.
+ \value Methods Add methods that aren't signals or slots.
+ \value Signals Add signals.
+ \value Slots Add slots.
+ \value Constructors Add constructors.
+ \value Properties Add properties.
+ \value Enumerators Add enumerators.
+ \value ClassInfos Add items of class information.
+ \value RelatedMetaObjects Add related meta objects.
+ \value StaticMetacall Add the static metacall function.
+ \value PublicMethods Add public methods (ignored for signals).
+ \value ProtectedMethods Add protected methods (ignored for signals).
+ \value PrivateMethods All private methods (ignored for signals).
+ \value AllMembers Add all members.
+ \value AllPrimaryMembers Add everything except the class name, super class, and static metacall function.
+*/
+
+// copied from moc's generator.cpp
+uint qvariant_nameToType(const char* name)
+{
+ if (!name)
+ return 0;
+
+ if (strcmp(name, "QVariant") == 0)
+ return 0xffffffff;
+ if (strcmp(name, "QCString") == 0)
+ return QMetaType::QByteArray;
+ if (strcmp(name, "Q_LLONG") == 0)
+ return QMetaType::LongLong;
+ if (strcmp(name, "Q_ULLONG") == 0)
+ return QMetaType::ULongLong;
+ if (strcmp(name, "QIconSet") == 0)
+ return QMetaType::QIcon;
+
+ uint tp = QMetaType::type(name);
+ return tp < QMetaType::User ? tp : 0;
+}
+
+/*
+ Returns true if the type is a QVariant types.
+*/
+bool isVariantType(const char* type)
+{
+ return qvariant_nameToType(type) != 0;
+}
+
+// copied from qmetaobject.cpp
+// do not touch without touching the moc as well
+enum PropertyFlags {
+ Invalid = 0x00000000,
+ Readable = 0x00000001,
+ Writable = 0x00000002,
+ Resettable = 0x00000004,
+ EnumOrFlag = 0x00000008,
+ StdCppSet = 0x00000100,
+// Override = 0x00000200,
+ Constant = 0x00000400,
+ Final = 0x00000800,
+ Designable = 0x00001000,
+ ResolveDesignable = 0x00002000,
+ Scriptable = 0x00004000,
+ ResolveScriptable = 0x00008000,
+ Stored = 0x00010000,
+ ResolveStored = 0x00020000,
+ Editable = 0x00040000,
+ ResolveEditable = 0x00080000,
+ User = 0x00100000,
+ ResolveUser = 0x00200000,
+ Notify = 0x00400000,
+ Revisioned = 0x00800000
+};
+
+enum MethodFlags {
+ AccessPrivate = 0x00,
+ AccessProtected = 0x01,
+ AccessPublic = 0x02,
+ AccessMask = 0x03, //mask
+
+ MethodMethod = 0x00,
+ MethodSignal = 0x04,
+ MethodSlot = 0x08,
+ MethodConstructor = 0x0c,
+ MethodTypeMask = 0x0c,
+
+ MethodCompatibility = 0x10,
+ MethodCloned = 0x20,
+ MethodScriptable = 0x40,
+ MethodRevisioned = 0x80
+};
+
+struct QMetaObjectPrivate
+{
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ int propertyCount, propertyData;
+ int enumeratorCount, enumeratorData;
+ int constructorCount, constructorData;
+ int flags;
+};
+
+static inline const QMetaObjectPrivate *priv(const uint* data)
+{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
+// end of copied lines from qmetaobject.cpp
+
+class QMetaMethodBuilderPrivate
+{
+public:
+ QMetaMethodBuilderPrivate
+ (QMetaMethod::MethodType _methodType,
+ const QByteArray& _signature,
+ const QByteArray& _returnType = QByteArray(),
+ QMetaMethod::Access _access = QMetaMethod::Public)
+ : signature(QMetaObject::normalizedSignature(_signature.constData())),
+ returnType(QMetaObject::normalizedType(_returnType)),
+ attributes(((int)_access) | (((int)_methodType) << 2))
+ {
+ }
+
+ QByteArray signature;
+ QByteArray returnType;
+ QList<QByteArray> parameterNames;
+ QByteArray tag;
+ int attributes;
+
+ QMetaMethod::MethodType methodType() const
+ {
+ return (QMetaMethod::MethodType)((attributes & MethodTypeMask) >> 2);
+ }
+
+ QMetaMethod::Access access() const
+ {
+ return (QMetaMethod::Access)(attributes & AccessMask);
+ }
+
+ void setAccess(QMetaMethod::Access value)
+ {
+ attributes = ((attributes & ~AccessMask) | (int)value);
+ }
+};
+
+class QMetaPropertyBuilderPrivate
+{
+public:
+ QMetaPropertyBuilderPrivate
+ (const QByteArray& _name, const QByteArray& _type, int notifierIdx=-1)
+ : name(_name),
+ type(QMetaObject::normalizedType(_type.constData())),
+ flags(Readable | Writable | Scriptable), notifySignal(-1)
+ {
+ if (notifierIdx >= 0) {
+ flags |= Notify;
+ notifySignal = notifierIdx;
+ }
+ }
+
+ QByteArray name;
+ QByteArray type;
+ int flags;
+ int notifySignal;
+
+ bool flag(int f) const
+ {
+ return ((flags & f) != 0);
+ }
+
+ void setFlag(int f, bool value)
+ {
+ if (value)
+ flags |= f;
+ else
+ flags &= ~f;
+ }
+};
+
+class QMetaEnumBuilderPrivate
+{
+public:
+ QMetaEnumBuilderPrivate(const QByteArray& _name)
+ : name(_name), isFlag(false)
+ {
+ }
+
+ QByteArray name;
+ bool isFlag;
+ QList<QByteArray> keys;
+ QList<int> values;
+};
+
+class QMetaObjectBuilderPrivate
+{
+public:
+ QMetaObjectBuilderPrivate()
+ : flags(0)
+ {
+ superClass = &QObject::staticMetaObject;
+ staticMetacallFunction = 0;
+ }
+
+ QByteArray className;
+ const QMetaObject *superClass;
+ QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction;
+ QList<QMetaMethodBuilderPrivate> methods;
+ QList<QMetaMethodBuilderPrivate> constructors;
+ QList<QMetaPropertyBuilderPrivate> properties;
+ QList<QByteArray> classInfoNames;
+ QList<QByteArray> classInfoValues;
+ QList<QMetaEnumBuilderPrivate> enumerators;
+#ifdef Q_NO_DATA_RELOCATION
+ QList<QMetaObjectAccessor> relatedMetaObjects;
+#else
+ QList<const QMetaObject *> relatedMetaObjects;
+#endif
+ int flags;
+};
+
+/*!
+ Constructs a new QMetaObjectBuilder.
+*/
+QMetaObjectBuilder::QMetaObjectBuilder()
+{
+ d = new QMetaObjectBuilderPrivate();
+}
+
+/*!
+ Constructs a new QMetaObjectBuilder which is a copy of the
+ meta object information in \a prototype. Note: the super class
+ contents for \a prototype are not copied, only the immediate
+ class that is defined by \a prototype.
+
+ The \a members parameter indicates which members of \a prototype
+ should be added. The default is AllMembers.
+
+ \sa addMetaObject()
+*/
+QMetaObjectBuilder::QMetaObjectBuilder
+ (const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members)
+{
+ d = new QMetaObjectBuilderPrivate();
+ addMetaObject(prototype, members);
+}
+
+/*!
+ Destroys this meta object builder.
+*/
+QMetaObjectBuilder::~QMetaObjectBuilder()
+{
+ delete d;
+}
+
+/*!
+ Returns the name of the class being constructed by this
+ meta object builder. The default value is an empty QByteArray.
+
+ \sa setClassName(), superClass()
+*/
+QByteArray QMetaObjectBuilder::className() const
+{
+ return d->className;
+}
+
+/*!
+ Sets the \a name of the class being constructed by this
+ meta object builder.
+
+ \sa className(), setSuperClass()
+*/
+void QMetaObjectBuilder::setClassName(const QByteArray& name)
+{
+ d->className = name;
+}
+
+/*!
+ Returns the superclass meta object of the class being constructed
+ by this meta object builder. The default value is the meta object
+ for QObject.
+
+ \sa setSuperClass(), className()
+*/
+const QMetaObject *QMetaObjectBuilder::superClass() const
+{
+ return d->superClass;
+}
+
+/*!
+ Sets the superclass meta object of the class being constructed
+ by this meta object builder to \a meta. The \a meta parameter
+ must not be null.
+
+ \sa superClass(), setClassName()
+*/
+void QMetaObjectBuilder::setSuperClass(const QMetaObject *meta)
+{
+ Q_ASSERT(meta);
+ d->superClass = meta;
+}
+
+/*!
+ Returns the flags of the class being constructed by this meta object
+ builder.
+
+ \sa setFlags()
+*/
+QMetaObjectBuilder::MetaObjectFlags QMetaObjectBuilder::flags() const
+{
+ return (QMetaObjectBuilder::MetaObjectFlags)d->flags;
+}
+
+/*!
+ Sets the \a flags of the class being constructed by this meta object
+ builder.
+
+ \sa flags()
+*/
+void QMetaObjectBuilder::setFlags(MetaObjectFlags flags)
+{
+ d->flags = flags;
+}
+
+/*!
+ Returns the number of methods in this class, excluding the number
+ of methods in the base class. These include signals and slots
+ as well as normal member functions.
+
+ \sa addMethod(), method(), removeMethod(), indexOfMethod()
+*/
+int QMetaObjectBuilder::methodCount() const
+{
+ return d->methods.size();
+}
+
+/*!
+ Returns the number of constructors in this class.
+
+ \sa addConstructor(), constructor(), removeConstructor(), indexOfConstructor()
+*/
+int QMetaObjectBuilder::constructorCount() const
+{
+ return d->constructors.size();
+}
+
+/*!
+ Returns the number of properties in this class, excluding the number
+ of properties in the base class.
+
+ \sa addProperty(), property(), removeProperty(), indexOfProperty()
+*/
+int QMetaObjectBuilder::propertyCount() const
+{
+ return d->properties.size();
+}
+
+/*!
+ Returns the number of enumerators in this class, excluding the
+ number of enumerators in the base class.
+
+ \sa addEnumerator(), enumerator(), removeEnumerator()
+ \sa indexOfEnumerator()
+*/
+int QMetaObjectBuilder::enumeratorCount() const
+{
+ return d->enumerators.size();
+}
+
+/*!
+ Returns the number of items of class information in this class,
+ exclusing the number of items of class information in the base class.
+
+ \sa addClassInfo(), classInfoName(), classInfoValue(), removeClassInfo()
+ \sa indexOfClassInfo()
+*/
+int QMetaObjectBuilder::classInfoCount() const
+{
+ return d->classInfoNames.size();
+}
+
+/*!
+ Returns the number of related meta objects that are associated
+ with this class.
+
+ Related meta objects are used when resolving the enumerated type
+ associated with a property, where the enumerated type is in a
+ different class from the property.
+
+ \sa addRelatedMetaObject(), relatedMetaObject()
+ \sa removeRelatedMetaObject()
+*/
+int QMetaObjectBuilder::relatedMetaObjectCount() const
+{
+ return d->relatedMetaObjects.size();
+}
+
+/*!
+ Adds a new public method to this class with the specified \a signature.
+ Returns an object that can be used to adjust the other attributes
+ of the method. The \a signature will be normalized before it is
+ added to the class.
+
+ \sa method(), methodCount(), removeMethod(), indexOfMethod()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QByteArray& signature)
+{
+ int index = d->methods.size();
+ d->methods.append(QMetaMethodBuilderPrivate(QMetaMethod::Method, signature));
+ return QMetaMethodBuilder(this, index);
+}
+
+/*!
+ Adds a new public method to this class with the specified
+ \a signature and \a returnType. Returns an object that can be
+ used to adjust the other attributes of the method. The \a signature
+ and \a returnType will be normalized before they are added to
+ the class. If \a returnType is empty, then it indicates that
+ the method has \c{void} as its return type.
+
+ \sa method(), methodCount(), removeMethod(), indexOfMethod()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addMethod
+ (const QByteArray& signature, const QByteArray& returnType)
+{
+ int index = d->methods.size();
+ d->methods.append(QMetaMethodBuilderPrivate
+ (QMetaMethod::Method, signature, returnType));
+ return QMetaMethodBuilder(this, index);
+}
+
+/*!
+ Adds a new public method to this class that has the same information as
+ \a prototype. This is used to clone the methods of an existing
+ QMetaObject. Returns an object that can be used to adjust the
+ attributes of the method.
+
+ This function will detect if \a prototype is an ordinary method,
+ signal, slot, or constructor and act accordingly.
+
+ \sa method(), methodCount(), removeMethod(), indexOfMethod()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addMethod(const QMetaMethod& prototype)
+{
+ QMetaMethodBuilder method;
+ if (prototype.methodType() == QMetaMethod::Method)
+ method = addMethod(prototype.signature());
+ else if (prototype.methodType() == QMetaMethod::Signal)
+ method = addSignal(prototype.signature());
+ else if (prototype.methodType() == QMetaMethod::Slot)
+ method = addSlot(prototype.signature());
+ else if (prototype.methodType() == QMetaMethod::Constructor)
+ method = addConstructor(prototype.signature());
+ method.setReturnType(prototype.typeName());
+ method.setParameterNames(prototype.parameterNames());
+ method.setTag(prototype.tag());
+ method.setAccess(prototype.access());
+ method.setAttributes(prototype.attributes());
+ return method;
+}
+
+/*!
+ Adds a new public slot to this class with the specified \a signature.
+ Returns an object that can be used to adjust the other attributes
+ of the slot. The \a signature will be normalized before it is
+ added to the class.
+
+ \sa addMethod(), addSignal(), indexOfSlot()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addSlot(const QByteArray& signature)
+{
+ int index = d->methods.size();
+ d->methods.append(QMetaMethodBuilderPrivate(QMetaMethod::Slot, signature));
+ return QMetaMethodBuilder(this, index);
+}
+
+/*!
+ Adds a new signal to this class with the specified \a signature.
+ Returns an object that can be used to adjust the other attributes
+ of the signal. The \a signature will be normalized before it is
+ added to the class.
+
+ \sa addMethod(), addSlot(), indexOfSignal()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addSignal(const QByteArray& signature)
+{
+ int index = d->methods.size();
+ d->methods.append(QMetaMethodBuilderPrivate
+ (QMetaMethod::Signal, signature, QByteArray(), QMetaMethod::Protected));
+ return QMetaMethodBuilder(this, index);
+}
+
+/*!
+ Adds a new constructor to this class with the specified \a signature.
+ Returns an object that can be used to adjust the other attributes
+ of the constructor. The \a signature will be normalized before it is
+ added to the class.
+
+ \sa constructor(), constructorCount(), removeConstructor()
+ \sa indexOfConstructor()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QByteArray& signature)
+{
+ int index = d->constructors.size();
+ d->constructors.append(QMetaMethodBuilderPrivate(QMetaMethod::Constructor, signature));
+ return QMetaMethodBuilder(this, -(index + 1));
+}
+
+/*!
+ Adds a new constructor to this class that has the same information as
+ \a prototype. This is used to clone the constructors of an existing
+ QMetaObject. Returns an object that can be used to adjust the
+ attributes of the constructor.
+
+ This function requires that \a prototype be a constructor.
+
+ \sa constructor(), constructorCount(), removeConstructor()
+ \sa indexOfConstructor()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::addConstructor(const QMetaMethod& prototype)
+{
+ Q_ASSERT(prototype.methodType() == QMetaMethod::Constructor);
+ QMetaMethodBuilder ctor = addConstructor(prototype.signature());
+ ctor.setReturnType(prototype.typeName());
+ ctor.setParameterNames(prototype.parameterNames());
+ ctor.setTag(prototype.tag());
+ ctor.setAccess(prototype.access());
+ ctor.setAttributes(prototype.attributes());
+ return ctor;
+}
+
+/*!
+ Adds a new readable/writable property to this class with the
+ specified \a name and \a type. Returns an object that can be used
+ to adjust the other attributes of the property. The \a type will
+ be normalized before it is added to the class. \a notifierId will
+ be registered as the property's \i notify signal.
+
+ \sa property(), propertyCount(), removeProperty(), indexOfProperty()
+*/
+QMetaPropertyBuilder QMetaObjectBuilder::addProperty
+ (const QByteArray& name, const QByteArray& type, int notifierId)
+{
+ int index = d->properties.size();
+ d->properties.append(QMetaPropertyBuilderPrivate(name, type, notifierId));
+ return QMetaPropertyBuilder(this, index);
+}
+
+/*!
+ Adds a new property to this class that has the same information as
+ \a prototype. This is used to clone the properties of an existing
+ QMetaObject. Returns an object that can be used to adjust the
+ attributes of the property.
+
+ \sa property(), propertyCount(), removeProperty(), indexOfProperty()
+*/
+QMetaPropertyBuilder QMetaObjectBuilder::addProperty(const QMetaProperty& prototype)
+{
+ QMetaPropertyBuilder property = addProperty(prototype.name(), prototype.typeName());
+ property.setReadable(prototype.isReadable());
+ property.setWritable(prototype.isWritable());
+ property.setResettable(prototype.isResettable());
+ property.setDesignable(prototype.isDesignable());
+ property.setScriptable(prototype.isScriptable());
+ property.setStored(prototype.isStored());
+ property.setEditable(prototype.isEditable());
+ property.setUser(prototype.isUser());
+ property.setStdCppSet(prototype.hasStdCppSet());
+ property.setEnumOrFlag(prototype.isEnumType());
+ property.setConstant(prototype.isConstant());
+ property.setFinal(prototype.isFinal());
+ if (prototype.hasNotifySignal()) {
+ // Find an existing method for the notify signal, or add a new one.
+ QMetaMethod method = prototype.notifySignal();
+ int index = indexOfMethod(method.signature());
+ if (index == -1)
+ index = addMethod(method).index();
+ d->properties[property._index].notifySignal = index;
+ d->properties[property._index].setFlag(Notify, true);
+ }
+ return property;
+}
+
+/*!
+ Adds a new enumerator to this class with the specified
+ \a name. Returns an object that can be used to adjust
+ the other attributes of the enumerator.
+
+ \sa enumerator(), enumeratorCount(), removeEnumerator(),
+ \sa indexOfEnumerator()
+*/
+QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QByteArray& name)
+{
+ int index = d->enumerators.size();
+ d->enumerators.append(QMetaEnumBuilderPrivate(name));
+ return QMetaEnumBuilder(this, index);
+}
+
+/*!
+ Adds a new enumerator to this class that has the same information as
+ \a prototype. This is used to clone the enumerators of an existing
+ QMetaObject. Returns an object that can be used to adjust the
+ attributes of the enumerator.
+
+ \sa enumerator(), enumeratorCount(), removeEnumerator(),
+ \sa indexOfEnumerator()
+*/
+QMetaEnumBuilder QMetaObjectBuilder::addEnumerator(const QMetaEnum& prototype)
+{
+ QMetaEnumBuilder en = addEnumerator(prototype.name());
+ en.setIsFlag(prototype.isFlag());
+ int count = prototype.keyCount();
+ for (int index = 0; index < count; ++index)
+ en.addKey(prototype.key(index), prototype.value(index));
+ return en;
+}
+
+/*!
+ Adds \a name and \a value as an item of class information to this class.
+ Returns the index of the new item of class information.
+
+ \sa classInfoCount(), classInfoName(), classInfoValue(), removeClassInfo()
+ \sa indexOfClassInfo()
+*/
+int QMetaObjectBuilder::addClassInfo(const QByteArray& name, const QByteArray& value)
+{
+ int index = d->classInfoNames.size();
+ d->classInfoNames += name;
+ d->classInfoValues += value;
+ return index;
+}
+
+/*!
+ Adds \a meta to this class as a related meta object. Returns
+ the index of the new related meta object entry.
+
+ Related meta objects are used when resolving the enumerated type
+ associated with a property, where the enumerated type is in a
+ different class from the property.
+
+ \sa relatedMetaObjectCount(), relatedMetaObject()
+ \sa removeRelatedMetaObject()
+*/
+#ifdef Q_NO_DATA_RELOCATION
+int QMetaObjectBuilder::addRelatedMetaObject(const QMetaObjectAccessor &meta)
+#else
+int QMetaObjectBuilder::addRelatedMetaObject(const QMetaObject *meta)
+#endif
+{
+ Q_ASSERT(meta);
+ int index = d->relatedMetaObjects.size();
+ d->relatedMetaObjects.append(meta);
+ return index;
+}
+
+/*!
+ Adds the contents of \a prototype to this meta object builder.
+ This function is useful for cloning the contents of an existing QMetaObject.
+
+ The \a members parameter indicates which members of \a prototype
+ should be added. The default is AllMembers.
+*/
+void QMetaObjectBuilder::addMetaObject
+ (const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members)
+{
+ Q_ASSERT(prototype);
+ int index;
+
+ if ((members & ClassName) != 0)
+ d->className = prototype->className();
+
+ if ((members & SuperClass) != 0)
+ d->superClass = prototype->superClass();
+
+ if ((members & (Methods | Signals | Slots)) != 0) {
+ for (index = prototype->methodOffset(); index < prototype->methodCount(); ++index) {
+ QMetaMethod method = prototype->method(index);
+ if (method.methodType() != QMetaMethod::Signal) {
+ if (method.access() == QMetaMethod::Public && (members & PublicMethods) == 0)
+ continue;
+ if (method.access() == QMetaMethod::Private && (members & PrivateMethods) == 0)
+ continue;
+ if (method.access() == QMetaMethod::Protected && (members & ProtectedMethods) == 0)
+ continue;
+ }
+ if (method.methodType() == QMetaMethod::Method && (members & Methods) != 0) {
+ addMethod(method);
+ } else if (method.methodType() == QMetaMethod::Signal &&
+ (members & Signals) != 0) {
+ addMethod(method);
+ } else if (method.methodType() == QMetaMethod::Slot &&
+ (members & Slots) != 0) {
+ addMethod(method);
+ }
+ }
+ }
+
+ if ((members & Constructors) != 0) {
+ for (index = 0; index < prototype->constructorCount(); ++index)
+ addConstructor(prototype->constructor(index));
+ }
+
+ if ((members & Properties) != 0) {
+ for (index = prototype->propertyOffset(); index < prototype->propertyCount(); ++index)
+ addProperty(prototype->property(index));
+ }
+
+ if ((members & Enumerators) != 0) {
+ for (index = prototype->enumeratorOffset(); index < prototype->enumeratorCount(); ++index)
+ addEnumerator(prototype->enumerator(index));
+ }
+
+ if ((members & ClassInfos) != 0) {
+ for (index = prototype->classInfoOffset(); index < prototype->classInfoCount(); ++index) {
+ QMetaClassInfo ci = prototype->classInfo(index);
+ addClassInfo(ci.name(), ci.value());
+ }
+ }
+
+ if ((members & RelatedMetaObjects) != 0) {
+#ifdef Q_NO_DATA_RELOCATION
+ const QMetaObjectAccessor *objects = 0;
+#else
+ const QMetaObject **objects;
+ if (priv(prototype->d.data)->revision < 2) {
+ objects = (const QMetaObject **)(prototype->d.extradata);
+ } else
+#endif
+ {
+ const QMetaObjectExtraData *extra = (const QMetaObjectExtraData *)(prototype->d.extradata);
+ if (extra)
+ objects = extra->objects;
+ else
+ objects = 0;
+ }
+ if (objects) {
+ while (*objects != 0) {
+ addRelatedMetaObject(*objects);
+ ++objects;
+ }
+ }
+ }
+
+ if ((members & StaticMetacall) != 0) {
+ if (priv(prototype->d.data)->revision >= 6) {
+ const QMetaObjectExtraData *extra =
+ (const QMetaObjectExtraData *)(prototype->d.extradata);
+ if (extra && extra->static_metacall)
+ setStaticMetacallFunction(extra->static_metacall);
+ }
+ }
+}
+
+/*!
+ Returns the method at \a index in this class.
+
+ \sa methodCount(), addMethod(), removeMethod(), indexOfMethod()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::method(int index) const
+{
+ if (index >= 0 && index < d->methods.size())
+ return QMetaMethodBuilder(this, index);
+ else
+ return QMetaMethodBuilder();
+}
+
+/*!
+ Returns the constructor at \a index in this class.
+
+ \sa methodCount(), addMethod(), removeMethod(), indexOfConstructor()
+*/
+QMetaMethodBuilder QMetaObjectBuilder::constructor(int index) const
+{
+ if (index >= 0 && index < d->constructors.size())
+ return QMetaMethodBuilder(this, -(index + 1));
+ else
+ return QMetaMethodBuilder();
+}
+
+/*!
+ Returns the property at \a index in this class.
+
+ \sa methodCount(), addMethod(), removeMethod(), indexOfProperty()
+*/
+QMetaPropertyBuilder QMetaObjectBuilder::property(int index) const
+{
+ if (index >= 0 && index < d->properties.size())
+ return QMetaPropertyBuilder(this, index);
+ else
+ return QMetaPropertyBuilder();
+}
+
+/*!
+ Returns the enumerator at \a index in this class.
+
+ \sa enumeratorCount(), addEnumerator(), removeEnumerator()
+ \sa indexOfEnumerator()
+*/
+QMetaEnumBuilder QMetaObjectBuilder::enumerator(int index) const
+{
+ if (index >= 0 && index < d->enumerators.size())
+ return QMetaEnumBuilder(this, index);
+ else
+ return QMetaEnumBuilder();
+}
+
+/*!
+ Returns the related meta object at \a index in this class.
+
+ Related meta objects are used when resolving the enumerated type
+ associated with a property, where the enumerated type is in a
+ different class from the property.
+
+ \sa relatedMetaObjectCount(), addRelatedMetaObject()
+ \sa removeRelatedMetaObject()
+*/
+const QMetaObject *QMetaObjectBuilder::relatedMetaObject(int index) const
+{
+ if (index >= 0 && index < d->relatedMetaObjects.size())
+#ifdef Q_NO_DATA_RELOCATION
+ return &((*(d->relatedMetaObjects[index]))());
+#else
+ return d->relatedMetaObjects[index];
+#endif
+ else
+ return 0;
+}
+
+/*!
+ Returns the name of the item of class information at \a index
+ in this class.
+
+ \sa classInfoCount(), addClassInfo(), classInfoValue(), removeClassInfo()
+ \sa indexOfClassInfo()
+*/
+QByteArray QMetaObjectBuilder::classInfoName(int index) const
+{
+ if (index >= 0 && index < d->classInfoNames.size())
+ return d->classInfoNames[index];
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns the value of the item of class information at \a index
+ in this class.
+
+ \sa classInfoCount(), addClassInfo(), classInfoName(), removeClassInfo()
+ \sa indexOfClassInfo()
+*/
+QByteArray QMetaObjectBuilder::classInfoValue(int index) const
+{
+ if (index >= 0 && index < d->classInfoValues.size())
+ return d->classInfoValues[index];
+ else
+ return QByteArray();
+}
+
+/*!
+ Removes the method at \a index from this class. The indices of
+ all following methods will be adjusted downwards by 1. If the
+ method is registered as a notify signal on a property, then the
+ notify signal will be removed from the property.
+
+ \sa methodCount(), addMethod(), method(), indexOfMethod()
+*/
+void QMetaObjectBuilder::removeMethod(int index)
+{
+ if (index >= 0 && index < d->methods.size()) {
+ d->methods.removeAt(index);
+ for (int prop = 0; prop < d->properties.size(); ++prop) {
+ // Adjust the indices of property notify signal references.
+ if (d->properties[prop].notifySignal == index) {
+ d->properties[prop].notifySignal = -1;
+ d->properties[prop].setFlag(Notify, false);
+ } else if (d->properties[prop].notifySignal > index)
+ (d->properties[prop].notifySignal)--;
+ }
+ }
+}
+
+/*!
+ Removes the constructor at \a index from this class. The indices of
+ all following constructors will be adjusted downwards by 1.
+
+ \sa constructorCount(), addConstructor(), constructor()
+ \sa indexOfConstructor()
+*/
+void QMetaObjectBuilder::removeConstructor(int index)
+{
+ if (index >= 0 && index < d->constructors.size())
+ d->constructors.removeAt(index);
+}
+
+/*!
+ Removes the property at \a index from this class. The indices of
+ all following properties will be adjusted downwards by 1.
+
+ \sa propertyCount(), addProperty(), property(), indexOfProperty()
+*/
+void QMetaObjectBuilder::removeProperty(int index)
+{
+ if (index >= 0 && index < d->properties.size())
+ d->properties.removeAt(index);
+}
+
+/*!
+ Removes the enumerator at \a index from this class. The indices of
+ all following enumerators will be adjusted downwards by 1.
+
+ \sa enumertorCount(), addEnumerator(), enumerator()
+ \sa indexOfEnumerator()
+*/
+void QMetaObjectBuilder::removeEnumerator(int index)
+{
+ if (index >= 0 && index < d->enumerators.size())
+ d->enumerators.removeAt(index);
+}
+
+/*!
+ Removes the item of class information at \a index from this class.
+ The indices of all following items will be adjusted downwards by 1.
+
+ \sa classInfoCount(), addClassInfo(), classInfoName(), classInfoValue()
+ \sa indexOfClassInfo()
+*/
+void QMetaObjectBuilder::removeClassInfo(int index)
+{
+ if (index >= 0 && index < d->classInfoNames.size()) {
+ d->classInfoNames.removeAt(index);
+ d->classInfoValues.removeAt(index);
+ }
+}
+
+/*!
+ Removes the related meta object at \a index from this class.
+ The indices of all following related meta objects will be adjusted
+ downwards by 1.
+
+ Related meta objects are used when resolving the enumerated type
+ associated with a property, where the enumerated type is in a
+ different class from the property.
+
+ \sa relatedMetaObjectCount(), addRelatedMetaObject()
+ \sa relatedMetaObject()
+*/
+void QMetaObjectBuilder::removeRelatedMetaObject(int index)
+{
+ if (index >= 0 && index < d->relatedMetaObjects.size())
+ d->relatedMetaObjects.removeAt(index);
+}
+
+/*!
+ Finds a method with the specified \a signature and returns its index;
+ otherwise returns -1. The \a signature will be normalized by this method.
+
+ \sa method(), methodCount(), addMethod(), removeMethod()
+*/
+int QMetaObjectBuilder::indexOfMethod(const QByteArray& signature)
+{
+ QByteArray sig = QMetaObject::normalizedSignature(signature);
+ for (int index = 0; index < d->methods.size(); ++index) {
+ if (sig == d->methods[index].signature)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds a signal with the specified \a signature and returns its index;
+ otherwise returns -1. The \a signature will be normalized by this method.
+
+ \sa indexOfMethod(), indexOfSlot()
+*/
+int QMetaObjectBuilder::indexOfSignal(const QByteArray& signature)
+{
+ QByteArray sig = QMetaObject::normalizedSignature(signature);
+ for (int index = 0; index < d->methods.size(); ++index) {
+ if (sig == d->methods[index].signature &&
+ d->methods[index].methodType() == QMetaMethod::Signal)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds a slot with the specified \a signature and returns its index;
+ otherwise returns -1. The \a signature will be normalized by this method.
+
+ \sa indexOfMethod(), indexOfSignal()
+*/
+int QMetaObjectBuilder::indexOfSlot(const QByteArray& signature)
+{
+ QByteArray sig = QMetaObject::normalizedSignature(signature);
+ for (int index = 0; index < d->methods.size(); ++index) {
+ if (sig == d->methods[index].signature &&
+ d->methods[index].methodType() == QMetaMethod::Slot)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds a constructor with the specified \a signature and returns its index;
+ otherwise returns -1. The \a signature will be normalized by this method.
+
+ \sa constructor(), constructorCount(), addConstructor(), removeConstructor()
+*/
+int QMetaObjectBuilder::indexOfConstructor(const QByteArray& signature)
+{
+ QByteArray sig = QMetaObject::normalizedSignature(signature);
+ for (int index = 0; index < d->constructors.size(); ++index) {
+ if (sig == d->constructors[index].signature)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds a property with the specified \a name and returns its index;
+ otherwise returns -1.
+
+ \sa property(), propertyCount(), addProperty(), removeProperty()
+*/
+int QMetaObjectBuilder::indexOfProperty(const QByteArray& name)
+{
+ for (int index = 0; index < d->properties.size(); ++index) {
+ if (name == d->properties[index].name)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds an enumerator with the specified \a name and returns its index;
+ otherwise returns -1.
+
+ \sa enumertor(), enumeratorCount(), addEnumerator(), removeEnumerator()
+*/
+int QMetaObjectBuilder::indexOfEnumerator(const QByteArray& name)
+{
+ for (int index = 0; index < d->enumerators.size(); ++index) {
+ if (name == d->enumerators[index].name)
+ return index;
+ }
+ return -1;
+}
+
+/*!
+ Finds an item of class information with the specified \a name and
+ returns its index; otherwise returns -1.
+
+ \sa classInfoName(), classInfoValue(), classInfoCount(), addClassInfo()
+ \sa removeClassInfo()
+*/
+int QMetaObjectBuilder::indexOfClassInfo(const QByteArray& name)
+{
+ for (int index = 0; index < d->classInfoNames.size(); ++index) {
+ if (name == d->classInfoNames[index])
+ return index;
+ }
+ return -1;
+}
+
+// Align on a specific type boundary.
+#define ALIGN(size,type) \
+ (size) = ((size) + sizeof(type) - 1) & ~(sizeof(type) - 1)
+
+// Build a string into a QMetaObject representation. Returns the
+// position in the string table where the string was placed.
+static int buildString
+ (char *buf, char *str, int *offset, const QByteArray& value, int empty)
+{
+ if (value.size() == 0 && empty >= 0)
+ return empty;
+ if (buf) {
+ memcpy(str + *offset, value.constData(), value.size());
+ str[*offset + value.size()] = '\0';
+ }
+ int posn = *offset;
+ *offset += value.size() + 1;
+ return posn;
+}
+
+// Build the parameter array string for a method.
+static QByteArray buildParameterNames
+ (const QByteArray& signature, const QList<QByteArray>& parameterNames)
+{
+ // If the parameter name list is specified, then concatenate them.
+ if (!parameterNames.isEmpty()) {
+ QByteArray names;
+ bool first = true;
+ foreach (const QByteArray &name, parameterNames) {
+ if (first)
+ first = false;
+ else
+ names += (char)',';
+ names += name;
+ }
+ return names;
+ }
+
+ // Count commas in the signature, excluding those inside template arguments.
+ int index = signature.indexOf('(');
+ if (index < 0)
+ return QByteArray();
+ ++index;
+ if (index >= signature.size())
+ return QByteArray();
+ if (signature[index] == ')')
+ return QByteArray();
+ int count = 1;
+ int brackets = 0;
+ while (index < signature.size() && signature[index] != ',') {
+ char ch = signature[index++];
+ if (ch == '<')
+ ++brackets;
+ else if (ch == '>')
+ --brackets;
+ else if (ch == ',' && brackets <= 0)
+ ++count;
+ }
+ return QByteArray(count - 1, ',');
+}
+
+// Build a QMetaObject in "buf" based on the information in "d".
+// If "buf" is null, then return the number of bytes needed to
+// build the QMetaObject. Returns -1 if the metaobject if
+// relocatable is set, but the metaobject contains extradata.
+static int buildMetaObject(QMetaObjectBuilderPrivate *d, char *buf,
+ bool relocatable)
+{
+ int size = 0;
+ int dataIndex;
+ int enumIndex;
+ int index;
+ bool hasNotifySignals = false;
+
+ if (relocatable &&
+ (d->relatedMetaObjects.size() > 0 || d->staticMetacallFunction))
+ return -1;
+
+ // Create the main QMetaObject structure at the start of the buffer.
+ QMetaObject *meta = reinterpret_cast<QMetaObject *>(buf);
+ size += sizeof(QMetaObject);
+ ALIGN(size, int);
+ if (buf) {
+ if (!relocatable) meta->d.superdata = d->superClass;
+ meta->d.extradata = 0;
+ }
+
+ // Populate the QMetaObjectPrivate structure.
+ QMetaObjectPrivate *pmeta
+ = reinterpret_cast<QMetaObjectPrivate *>(buf + size);
+ int pmetaSize = size;
+ dataIndex = 13; // Number of fields in the QMetaObjectPrivate.
+ for (index = 0; index < d->properties.size(); ++index) {
+ if (d->properties[index].notifySignal != -1) {
+ hasNotifySignals = true;
+ break;
+ }
+ }
+ if (buf) {
+ pmeta->revision = 3;
+ pmeta->flags = d->flags;
+ pmeta->className = 0; // Class name is always the first string.
+
+ pmeta->classInfoCount = d->classInfoNames.size();
+ pmeta->classInfoData = dataIndex;
+ dataIndex += 2 * d->classInfoNames.size();
+
+ pmeta->methodCount = d->methods.size();
+ pmeta->methodData = dataIndex;
+ dataIndex += 5 * d->methods.size();
+
+ pmeta->propertyCount = d->properties.size();
+ pmeta->propertyData = dataIndex;
+ dataIndex += 3 * d->properties.size();
+ if (hasNotifySignals)
+ dataIndex += d->properties.size();
+
+ pmeta->enumeratorCount = d->enumerators.size();
+ pmeta->enumeratorData = dataIndex;
+ dataIndex += 4 * d->enumerators.size();
+
+ pmeta->constructorCount = d->constructors.size();
+ pmeta->constructorData = dataIndex;
+ dataIndex += 5 * d->constructors.size();
+ } else {
+ dataIndex += 2 * d->classInfoNames.size();
+ dataIndex += 5 * d->methods.size();
+ dataIndex += 3 * d->properties.size();
+ if (hasNotifySignals)
+ dataIndex += d->properties.size();
+ dataIndex += 4 * d->enumerators.size();
+ dataIndex += 5 * d->constructors.size();
+ }
+
+ // Allocate space for the enumerator key names and values.
+ enumIndex = dataIndex;
+ for (index = 0; index < d->enumerators.size(); ++index) {
+ QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]);
+ dataIndex += 2 * enumerator->keys.size();
+ }
+
+ // Zero terminator at the end of the data offset table.
+ ++dataIndex;
+
+ // Find the start of the data and string tables.
+ int *data = reinterpret_cast<int *>(pmeta);
+ size += dataIndex * sizeof(int);
+ char *str = reinterpret_cast<char *>(buf + size);
+ if (buf) {
+ if (relocatable) {
+ meta->d.stringdata = reinterpret_cast<const char *>((quintptr)size);
+ meta->d.data = reinterpret_cast<uint *>((quintptr)pmetaSize);
+ } else {
+ meta->d.stringdata = str;
+ meta->d.data = reinterpret_cast<uint *>(data);
+ }
+ }
+
+ // Reset the current data position to just past the QMetaObjectPrivate.
+ dataIndex = 13;
+
+ // Add the class name to the string table.
+ int offset = 0;
+ buildString(buf, str, &offset, d->className, -1);
+
+ // Add a common empty string, which is used to indicate "void"
+ // method returns, empty tag strings, etc.
+ int empty = buildString(buf, str, &offset, QByteArray(), -1);
+
+ // Output the class infos,
+ for (index = 0; index < d->classInfoNames.size(); ++index) {
+ int name = buildString(buf, str, &offset, d->classInfoNames[index], empty);
+ int value = buildString(buf, str, &offset, d->classInfoValues[index], empty);
+ if (buf) {
+ data[dataIndex] = name;
+ data[dataIndex + 1] = value;
+ }
+ dataIndex += 2;
+ }
+
+ // Output the methods in the class.
+ for (index = 0; index < d->methods.size(); ++index) {
+ QMetaMethodBuilderPrivate *method = &(d->methods[index]);
+ int sig = buildString(buf, str, &offset, method->signature, empty);
+ int params;
+ QByteArray names = buildParameterNames
+ (method->signature, method->parameterNames);
+ params = buildString(buf, str, &offset, names, empty);
+ int ret = buildString(buf, str, &offset, method->returnType, empty);
+ int tag = buildString(buf, str, &offset, method->tag, empty);
+ int attrs = method->attributes;
+ if (buf) {
+ data[dataIndex] = sig;
+ data[dataIndex + 1] = params;
+ data[dataIndex + 2] = ret;
+ data[dataIndex + 3] = tag;
+ data[dataIndex + 4] = attrs;
+ }
+ dataIndex += 5;
+ }
+
+ // Output the properties in the class.
+ for (index = 0; index < d->properties.size(); ++index) {
+ QMetaPropertyBuilderPrivate *prop = &(d->properties[index]);
+ int name = buildString(buf, str, &offset, prop->name, empty);
+ int type = buildString(buf, str, &offset, prop->type, empty);
+ int flags = prop->flags;
+
+ if (!isVariantType(prop->type)) {
+ flags |= EnumOrFlag;
+ } else {
+ flags |= qvariant_nameToType(prop->type) << 24;
+ }
+
+ if (buf) {
+ data[dataIndex] = name;
+ data[dataIndex + 1] = type;
+ data[dataIndex + 2] = flags;
+ }
+ dataIndex += 3;
+ }
+ if (hasNotifySignals) {
+ for (index = 0; index < d->properties.size(); ++index) {
+ QMetaPropertyBuilderPrivate *prop = &(d->properties[index]);
+ if (buf) {
+ if (prop->notifySignal != -1)
+ data[dataIndex] = prop->notifySignal;
+ else
+ data[dataIndex] = 0;
+ }
+ ++dataIndex;
+ }
+ }
+
+ // Output the enumerators in the class.
+ for (index = 0; index < d->enumerators.size(); ++index) {
+ QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]);
+ int name = buildString(buf, str, &offset, enumerator->name, empty);
+ int isFlag = (int)(enumerator->isFlag);
+ int count = enumerator->keys.size();
+ int enumOffset = enumIndex;
+ if (buf) {
+ data[dataIndex] = name;
+ data[dataIndex + 1] = isFlag;
+ data[dataIndex + 2] = count;
+ data[dataIndex + 3] = enumOffset;
+ }
+ for (int key = 0; key < count; ++key) {
+ int keyIndex = buildString(buf, str, &offset, enumerator->keys[key], empty);
+ if (buf) {
+ data[enumOffset++] = keyIndex;
+ data[enumOffset++] = enumerator->values[key];
+ }
+ }
+ dataIndex += 4;
+ enumIndex += 2 * count;
+ }
+
+ // Output the constructors in the class.
+ for (index = 0; index < d->constructors.size(); ++index) {
+ QMetaMethodBuilderPrivate *method = &(d->constructors[index]);
+ int sig = buildString(buf, str, &offset, method->signature, empty);
+ int params;
+ QByteArray names = buildParameterNames
+ (method->signature, method->parameterNames);
+ params = buildString(buf, str, &offset, names, empty);
+ int ret = buildString(buf, str, &offset, method->returnType, empty);
+ int tag = buildString(buf, str, &offset, method->tag, empty);
+ int attrs = method->attributes;
+ if (buf) {
+ data[dataIndex] = sig;
+ data[dataIndex + 1] = params;
+ data[dataIndex + 2] = ret;
+ data[dataIndex + 3] = tag;
+ data[dataIndex + 4] = attrs;
+ }
+ dataIndex += 5;
+ }
+
+ // One more empty string to act as a terminator.
+ buildString(buf, str, &offset, QByteArray(), -1);
+ size += offset;
+
+ // Output the zero terminator in the data array.
+ if (buf)
+ data[enumIndex] = 0;
+
+ // Create the extradata block if we need one.
+ if (d->relatedMetaObjects.size() > 0 || d->staticMetacallFunction) {
+ ALIGN(size, QMetaObject **);
+ ALIGN(size, QMetaObjectBuilder::StaticMetacallFunction);
+ QMetaObjectExtraData *extra =
+ reinterpret_cast<QMetaObjectExtraData *>(buf + size);
+ size += sizeof(QMetaObjectExtraData);
+ ALIGN(size, QMetaObject *);
+#ifdef Q_NO_DATA_RELOCATION
+ QMetaObjectAccessor *objects =
+ reinterpret_cast<QMetaObjectAccessor *>(buf + size);
+#else
+ const QMetaObject **objects =
+ reinterpret_cast<const QMetaObject **>(buf + size);
+#endif
+ if (buf) {
+ if (d->relatedMetaObjects.size() > 0) {
+ extra->objects = objects;
+ for (index = 0; index < d->relatedMetaObjects.size(); ++index)
+ objects[index] = d->relatedMetaObjects[index];
+ objects[index] = 0;
+ } else {
+ extra->objects = 0;
+ }
+ extra->static_metacall = d->staticMetacallFunction;
+ meta->d.extradata = reinterpret_cast<void *>(extra);
+ }
+ if (d->relatedMetaObjects.size() > 0)
+ size += sizeof(QMetaObject *) * (d->relatedMetaObjects.size() + 1);
+ }
+
+ // Align the final size and return it.
+ ALIGN(size, void *);
+ return size;
+}
+
+/*!
+ Converts this meta object builder into a concrete QMetaObject.
+ The return value should be deallocated using qFree() once it
+ is no longer needed.
+
+ The returned meta object is a snapshot of the state of the
+ QMetaObjectBuilder. Any further modifications to the QMetaObjectBuilder
+ will not be reflected in previous meta objects returned by
+ this method.
+*/
+QMetaObject *QMetaObjectBuilder::toMetaObject() const
+{
+ int size = buildMetaObject(d, 0, false);
+ char *buf = reinterpret_cast<char *>(qMalloc(size));
+ buildMetaObject(d, buf, false);
+ return reinterpret_cast<QMetaObject *>(buf);
+}
+
+/*
+ \internal
+
+ Converts this meta object builder into relocatable data. This data can
+ be stored, copied and later passed to fromRelocatableData() to create a
+ concrete QMetaObject.
+
+ The data is specific to the architecture on which it was created, but is not
+ specific to the process that created it. Not all meta object builder's can
+ be converted to data in this way. If \a ok is provided, it will be set to
+ true if the conversion succeeds, and false otherwise. If a
+ staticMetacallFunction() or any relatedMetaObject()'s are specified the
+ conversion to relocatable data will fail.
+*/
+QByteArray QMetaObjectBuilder::toRelocatableData(bool *ok) const
+{
+ int size = buildMetaObject(d, 0, true);
+ if (size == -1) {
+ if (ok) *ok = false;
+ return QByteArray();
+ }
+
+ QByteArray data;
+ data.resize(size);
+ char *buf = data.data();
+ buildMetaObject(d, buf, true);
+ if (ok) *ok = true;
+ return data;
+}
+
+/*
+ \internal
+
+ Sets the \a data returned from toRelocatableData() onto a concrete
+ QMetaObject instance, \a output. As the meta object's super class is not
+ saved in the relocatable data, it must be passed as \a superClass.
+*/
+void QMetaObjectBuilder::fromRelocatableData(QMetaObject *output,
+ const QMetaObject *superclass,
+ const QByteArray &data)
+{
+ if (!output)
+ return;
+
+ const char *buf = data.constData();
+ const QMetaObject *dataMo = reinterpret_cast<const QMetaObject *>(buf);
+
+ quintptr stringdataOffset = (quintptr)dataMo->d.stringdata;
+ quintptr dataOffset = (quintptr)dataMo->d.data;
+
+ output->d.superdata = superclass;
+ output->d.stringdata = buf + stringdataOffset;
+ output->d.data = reinterpret_cast<const uint *>(buf + dataOffset);
+}
+
+/*!
+ \typedef QMetaObjectBuilder::StaticMetacallFunction
+
+ Typedef for static metacall functions. The three parameters are
+ the call type value, the constructor index, and the
+ array of parameters.
+*/
+
+/*!
+ Returns the static metacall function to use to construct objects
+ of this class. The default value is null.
+
+ \sa setStaticMetacallFunction()
+*/
+QMetaObjectBuilder::StaticMetacallFunction QMetaObjectBuilder::staticMetacallFunction() const
+{
+ return d->staticMetacallFunction;
+}
+
+/*!
+ Sets the static metacall function to use to construct objects
+ of this class to \a value. The default value is null.
+
+ \sa staticMetacallFunction()
+*/
+void QMetaObjectBuilder::setStaticMetacallFunction
+ (QMetaObjectBuilder::StaticMetacallFunction value)
+{
+ d->staticMetacallFunction = value;
+}
+
+#ifndef QT_NO_DATASTREAM
+
+/*!
+ Serializes the contents of the meta object builder onto \a stream.
+
+ \sa deserialize()
+*/
+void QMetaObjectBuilder::serialize(QDataStream& stream) const
+{
+ int index;
+
+ // Write the class and super class names.
+ stream << d->className;
+ if (d->superClass)
+ stream << QByteArray(d->superClass->className());
+ else
+ stream << QByteArray();
+
+ // Write the counts for each type of class member.
+ stream << d->classInfoNames.size();
+ stream << d->methods.size();
+ stream << d->properties.size();
+ stream << d->enumerators.size();
+ stream << d->constructors.size();
+ stream << d->relatedMetaObjects.size();
+
+ // Write the items of class information.
+ for (index = 0; index < d->classInfoNames.size(); ++index) {
+ stream << d->classInfoNames[index];
+ stream << d->classInfoValues[index];
+ }
+
+ // Write the methods.
+ for (index = 0; index < d->methods.size(); ++index) {
+ const QMetaMethodBuilderPrivate *method = &(d->methods[index]);
+ stream << method->signature;
+ stream << method->returnType;
+ stream << method->parameterNames;
+ stream << method->tag;
+ stream << method->attributes;
+ }
+
+ // Write the properties.
+ for (index = 0; index < d->properties.size(); ++index) {
+ const QMetaPropertyBuilderPrivate *property = &(d->properties[index]);
+ stream << property->name;
+ stream << property->type;
+ stream << property->flags;
+ stream << property->notifySignal;
+ }
+
+ // Write the enumerators.
+ for (index = 0; index < d->enumerators.size(); ++index) {
+ const QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]);
+ stream << enumerator->name;
+ stream << enumerator->isFlag;
+ stream << enumerator->keys;
+ stream << enumerator->values;
+ }
+
+ // Write the constructors.
+ for (index = 0; index < d->constructors.size(); ++index) {
+ const QMetaMethodBuilderPrivate *method = &(d->constructors[index]);
+ stream << method->signature;
+ stream << method->returnType;
+ stream << method->parameterNames;
+ stream << method->tag;
+ stream << method->attributes;
+ }
+
+ // Write the related meta objects.
+#ifdef Q_NO_DATA_RELOCATION
+ //the related meta objects will be function pointers
+ //which you have to add to the builder manually.
+ //e.g.
+ //builder2.addRelatedMetaObject(QLocale::getStaticMetaObject);
+#else
+ for (index = 0; index < d->relatedMetaObjects.size(); ++index) {
+ const QMetaObject *meta = d->relatedMetaObjects[index];
+ stream << QByteArray(meta->className());
+ }
+#endif
+
+ // Add an extra empty QByteArray for additional data in future versions.
+ // This should help maintain backwards compatibility, allowing older
+ // versions to read newer data.
+ stream << QByteArray();
+}
+
+// Resolve a class name using the name reference map.
+static const QMetaObject *resolveClassName
+ (const QMap<QByteArray, const QMetaObject *>& references,
+ const QByteArray& name)
+{
+ if (name == QByteArray("QObject"))
+ return &QObject::staticMetaObject;
+ else
+ return references.value(name, 0);
+}
+
+/*!
+ Deserializes a meta object builder from \a stream into
+ this meta object builder.
+
+ The \a references parameter specifies a mapping from class names
+ to QMetaObject instances for resolving the super class name and
+ related meta objects in the object that is deserialized.
+ The meta object for QObject is implicitly added to \a references
+ and does not need to be supplied.
+
+ The QDataStream::status() value on \a stream will be set to
+ QDataStream::ReadCorruptData if the input data is corrupt.
+ The status will be set to QDataStream::ReadPastEnd if the
+ input was exhausted before the full meta object was read.
+
+ \sa serialize()
+*/
+void QMetaObjectBuilder::deserialize
+ (QDataStream& stream,
+ const QMap<QByteArray, const QMetaObject *>& references)
+{
+ QByteArray name;
+ const QMetaObject *cl;
+ int index;
+
+ // Clear all members in the builder to their default states.
+ d->className.clear();
+ d->superClass = &QObject::staticMetaObject;
+ d->classInfoNames.clear();
+ d->classInfoValues.clear();
+ d->methods.clear();
+ d->properties.clear();
+ d->enumerators.clear();
+ d->constructors.clear();
+ d->relatedMetaObjects.clear();
+ d->staticMetacallFunction = 0;
+
+ // Read the class and super class names.
+ stream >> d->className;
+ stream >> name;
+ if (name.isEmpty()) {
+ d->superClass = 0;
+ } else if ((cl = resolveClassName(references, name)) != 0) {
+ d->superClass = cl;
+ } else {
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+
+ // Read the counts for each type of class member.
+ int classInfoCount, methodCount, propertyCount;
+ int enumeratorCount, constructorCount, relatedMetaObjectCount;
+ stream >> classInfoCount;
+ stream >> methodCount;
+ stream >> propertyCount;
+ stream >> enumeratorCount;
+ stream >> constructorCount;
+ stream >> relatedMetaObjectCount;
+ if (classInfoCount < 0 || methodCount < 0 ||
+ propertyCount < 0 || enumeratorCount < 0 ||
+ constructorCount < 0 || relatedMetaObjectCount < 0) {
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+
+ // Read the items of class information.
+ for (index = 0; index < classInfoCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ QByteArray value;
+ stream >> name;
+ stream >> value;
+ addClassInfo(name, value);
+ }
+
+ // Read the member methods.
+ for (index = 0; index < methodCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ stream >> name;
+ addMethod(name);
+ QMetaMethodBuilderPrivate *method = &(d->methods[index]);
+ stream >> method->returnType;
+ stream >> method->parameterNames;
+ stream >> method->tag;
+ stream >> method->attributes;
+ if (method->methodType() == QMetaMethod::Constructor) {
+ // Cannot add a constructor in this set of methods.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ }
+
+ // Read the properties.
+ for (index = 0; index < propertyCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ QByteArray type;
+ stream >> name;
+ stream >> type;
+ addProperty(name, type);
+ QMetaPropertyBuilderPrivate *property = &(d->properties[index]);
+ stream >> property->flags;
+ stream >> property->notifySignal;
+ if (property->notifySignal < -1 ||
+ property->notifySignal >= d->methods.size()) {
+ // Notify signal method index is out of range.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ if (property->notifySignal >= 0 &&
+ d->methods[property->notifySignal].methodType() != QMetaMethod::Signal) {
+ // Notify signal method index does not refer to a signal.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ }
+
+ // Read the enumerators.
+ for (index = 0; index < enumeratorCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ stream >> name;
+ addEnumerator(name);
+ QMetaEnumBuilderPrivate *enumerator = &(d->enumerators[index]);
+ stream >> enumerator->isFlag;
+ stream >> enumerator->keys;
+ stream >> enumerator->values;
+ if (enumerator->keys.size() != enumerator->values.size()) {
+ // Mismatch between number of keys and number of values.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ }
+
+ // Read the constructor methods.
+ for (index = 0; index < constructorCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ stream >> name;
+ addConstructor(name);
+ QMetaMethodBuilderPrivate *method = &(d->constructors[index]);
+ stream >> method->returnType;
+ stream >> method->parameterNames;
+ stream >> method->tag;
+ stream >> method->attributes;
+ if (method->methodType() != QMetaMethod::Constructor) {
+ // The type must be Constructor.
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ }
+
+ // Read the related meta objects.
+#ifdef Q_NO_DATA_RELOCATION
+ //the related meta objects will be function pointers
+ //which you have to add to the builder manually.
+ //e.g.
+ //builder2.addRelatedMetaObject(QLocale::getStaticMetaObject);
+#else
+ for (index = 0; index < relatedMetaObjectCount; ++index) {
+ if (stream.status() != QDataStream::Ok)
+ return;
+ stream >> name;
+ cl = resolveClassName(references, name);
+ if (!cl) {
+ stream.setStatus(QDataStream::ReadCorruptData);
+ return;
+ }
+ addRelatedMetaObject(cl);
+ }
+#endif
+
+ // Read the extra data block, which is reserved for future use.
+ stream >> name;
+}
+
+#endif // !QT_NO_DATASTREAM
+
+/*!
+ \class QMetaMethodBuilder
+ \internal
+ \brief The QMetaMethodBuilder class enables modifications to a method definition on a meta object builder.
+*/
+
+QMetaMethodBuilderPrivate *QMetaMethodBuilder::d_func() const
+{
+ // Positive indices indicate methods, negative indices indicate constructors.
+ if (_mobj && _index >= 0 && _index < _mobj->d->methods.size())
+ return &(_mobj->d->methods[_index]);
+ else if (_mobj && -_index >= 1 && -_index <= _mobj->d->constructors.size())
+ return &(_mobj->d->constructors[(-_index) - 1]);
+ else
+ return 0;
+}
+
+/*!
+ \fn QMetaMethodBuilder::QMetaMethodBuilder()
+ \internal
+*/
+
+/*!
+ Returns the index of this method within its QMetaObjectBuilder.
+*/
+int QMetaMethodBuilder::index() const
+{
+ if (_index >= 0)
+ return _index; // Method, signal, or slot
+ else
+ return (-_index) - 1; // Constructor
+}
+
+/*!
+ Returns the type of this method (signal, slot, method, or constructor).
+*/
+QMetaMethod::MethodType QMetaMethodBuilder::methodType() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->methodType();
+ else
+ return QMetaMethod::Method;
+}
+
+/*!
+ Returns the signature of this method.
+
+ \sa parameterNames(), returnType()
+*/
+QByteArray QMetaMethodBuilder::signature() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->signature;
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns the return type for this method; empty if the method's
+ return type is \c{void}.
+
+ \sa setReturnType(), signature()
+*/
+QByteArray QMetaMethodBuilder::returnType() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->returnType;
+ else
+ return QByteArray();
+}
+
+/*!
+ Sets the return type for this method to \a value. If \a value
+ is empty, then the method's return type is \c{void}. The \a value
+ will be normalized before it is added to the method.
+
+ \sa returnType(), signature()
+*/
+void QMetaMethodBuilder::setReturnType(const QByteArray& value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ d->returnType = QMetaObject::normalizedType(value);
+}
+
+/*!
+ Returns the list of parameter names for this method.
+
+ \sa setParameterNames()
+*/
+QList<QByteArray> QMetaMethodBuilder::parameterNames() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->parameterNames;
+ else
+ return QList<QByteArray>();
+}
+
+/*!
+ Sets the list of parameter names for this method to \a value.
+
+ \sa parameterNames()
+*/
+void QMetaMethodBuilder::setParameterNames(const QList<QByteArray>& value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ d->parameterNames = value;
+}
+
+/*!
+ Returns the tag associated with this method.
+
+ \sa setTag()
+*/
+QByteArray QMetaMethodBuilder::tag() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->tag;
+ else
+ return QByteArray();
+}
+
+/*!
+ Sets the tag associated with this method to \a value.
+
+ \sa setTag()
+*/
+void QMetaMethodBuilder::setTag(const QByteArray& value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ d->tag = value;
+}
+
+/*!
+ Returns the access specification of this method (private, protected,
+ or public). The default value is QMetaMethod::Public for methods,
+ slots, and constructors. The default value is QMetaMethod::Protected
+ for signals.
+
+ \sa setAccess()
+*/
+QMetaMethod::Access QMetaMethodBuilder::access() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return d->access();
+ else
+ return QMetaMethod::Public;
+}
+
+/*!
+ Sets the access specification of this method (private, protected,
+ or public) to \a value. If the method is a signal, this function
+ will be ignored.
+
+ \sa access()
+*/
+void QMetaMethodBuilder::setAccess(QMetaMethod::Access value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d && d->methodType() != QMetaMethod::Signal)
+ d->setAccess(value);
+}
+
+/*!
+ Returns the additional attributes for this method.
+
+ \sa setAttributes()
+*/
+int QMetaMethodBuilder::attributes() const
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ return (d->attributes >> 4);
+ else
+ return 0;
+}
+
+/*!
+ Sets the additional attributes for this method to \a value.
+
+ \sa attributes()
+*/
+void QMetaMethodBuilder::setAttributes(int value)
+{
+ QMetaMethodBuilderPrivate *d = d_func();
+ if (d)
+ d->attributes = ((d->attributes & 0x0f) | (value << 4));
+}
+
+/*!
+ \class QMetaPropertyBuilder
+ \internal
+ \brief The QMetaPropertyBuilder class enables modifications to a property definition on a meta object builder.
+*/
+
+QMetaPropertyBuilderPrivate *QMetaPropertyBuilder::d_func() const
+{
+ if (_mobj && _index >= 0 && _index < _mobj->d->properties.size())
+ return &(_mobj->d->properties[_index]);
+ else
+ return 0;
+}
+
+/*!
+ \fn QMetaPropertyBuilder::QMetaPropertyBuilder()
+ \internal
+*/
+
+/*!
+ \fn int QMetaPropertyBuilder::index() const
+
+ Returns the index of this property within its QMetaObjectBuilder.
+*/
+
+/*!
+ Returns the name associated with this property.
+
+ \sa type()
+*/
+QByteArray QMetaPropertyBuilder::name() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->name;
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns the type associated with this property.
+
+ \sa name()
+*/
+QByteArray QMetaPropertyBuilder::type() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->type;
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns true if this property has a notify signal; false otherwise.
+
+ \sa notifySignal(), setNotifySignal(), removeNotifySignal()
+*/
+bool QMetaPropertyBuilder::hasNotifySignal() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Notify);
+ else
+ return false;
+}
+
+/*!
+ Returns the notify signal associated with this property.
+
+ \sa hasNotifySignal(), setNotifySignal(), removeNotifySignal()
+*/
+QMetaMethodBuilder QMetaPropertyBuilder::notifySignal() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d && d->notifySignal >= 0)
+ return QMetaMethodBuilder(_mobj, d->notifySignal);
+ else
+ return QMetaMethodBuilder();
+}
+
+/*!
+ Sets the notify signal associated with this property to \a value.
+
+ \sa hasNotifySignal(), notifySignal(), removeNotifySignal()
+*/
+void QMetaPropertyBuilder::setNotifySignal(const QMetaMethodBuilder& value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d) {
+ if (value._mobj) {
+ d->notifySignal = value._index;
+ d->setFlag(Notify, true);
+ } else {
+ d->notifySignal = -1;
+ d->setFlag(Notify, false);
+ }
+ }
+}
+
+/*!
+ Removes the notify signal from this property.
+
+ \sa hasNotifySignal(), notifySignal(), setNotifySignal()
+*/
+void QMetaPropertyBuilder::removeNotifySignal()
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d) {
+ d->notifySignal = -1;
+ d->setFlag(Notify, false);
+ }
+}
+
+/*!
+ Returns true if this property is readable; otherwise returns false.
+ The default value is true.
+
+ \sa setReadable(), isWritable()
+*/
+bool QMetaPropertyBuilder::isReadable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Readable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if this property is writable; otherwise returns false.
+ The default value is true.
+
+ \sa setWritable(), isReadable()
+*/
+bool QMetaPropertyBuilder::isWritable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Writable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if this property can be reset to a default value; otherwise
+ returns false. The default value is false.
+
+ \sa setResettable()
+*/
+bool QMetaPropertyBuilder::isResettable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Resettable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if this property is designable; otherwise returns false.
+ This default value is false.
+
+ \sa setDesignable(), isScriptable(), isStored()
+*/
+bool QMetaPropertyBuilder::isDesignable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Designable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is scriptable; otherwise returns false.
+ This default value is true.
+
+ \sa setScriptable(), isDesignable(), isStored()
+*/
+bool QMetaPropertyBuilder::isScriptable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Scriptable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is stored; otherwise returns false.
+ This default value is false.
+
+ \sa setStored(), isDesignable(), isScriptable()
+*/
+bool QMetaPropertyBuilder::isStored() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Stored);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is editable; otherwise returns false.
+ This default value is false.
+
+ \sa setEditable(), isDesignable(), isScriptable(), isStored()
+*/
+bool QMetaPropertyBuilder::isEditable() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Editable);
+ else
+ return false;
+}
+
+/*!
+ Returns true if this property is designated as the \c USER
+ property, i.e., the one that the user can edit or that is
+ significant in some other way. Otherwise it returns
+ false. This default value is false.
+
+ \sa setUser(), isDesignable(), isScriptable()
+*/
+bool QMetaPropertyBuilder::isUser() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(User);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property has a C++ setter function that
+ follows Qt's standard "name" / "setName" pattern. Designer and uic
+ query hasStdCppSet() in order to avoid expensive
+ QObject::setProperty() calls. All properties in Qt [should] follow
+ this pattern. The default value is false.
+
+ \sa setStdCppSet()
+*/
+bool QMetaPropertyBuilder::hasStdCppSet() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(StdCppSet);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is an enumerator or flag type;
+ otherwise returns false. This default value is false.
+
+ \sa setEnumOrFlag()
+*/
+bool QMetaPropertyBuilder::isEnumOrFlag() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(EnumOrFlag);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is constant; otherwise returns false.
+ The default value is false.
+*/
+bool QMetaPropertyBuilder::isConstant() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Constant);
+ else
+ return false;
+}
+
+/*!
+ Returns true if the property is final; otherwise returns false.
+ The default value is false.
+*/
+bool QMetaPropertyBuilder::isFinal() const
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ return d->flag(Final);
+ else
+ return false;
+}
+
+/*!
+ Sets this property to readable if \a value is true.
+
+ \sa isReadable(), setWritable()
+*/
+void QMetaPropertyBuilder::setReadable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Readable, value);
+}
+
+/*!
+ Sets this property to writable if \a value is true.
+
+ \sa isWritable(), setReadable()
+*/
+void QMetaPropertyBuilder::setWritable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Writable, value);
+}
+
+/*!
+ Sets this property to resettable if \a value is true.
+
+ \sa isResettable()
+*/
+void QMetaPropertyBuilder::setResettable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Resettable, value);
+}
+
+/*!
+ Sets this property to designable if \a value is true.
+
+ \sa isDesignable(), setScriptable(), setStored()
+*/
+void QMetaPropertyBuilder::setDesignable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Designable, value);
+}
+
+/*!
+ Sets this property to scriptable if \a value is true.
+
+ \sa isScriptable(), setDesignable(), setStored()
+*/
+void QMetaPropertyBuilder::setScriptable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Scriptable, value);
+}
+
+/*!
+ Sets this property to storable if \a value is true.
+
+ \sa isStored(), setDesignable(), setScriptable()
+*/
+void QMetaPropertyBuilder::setStored(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Stored, value);
+}
+
+/*!
+ Sets this property to editable if \a value is true.
+
+ \sa isEditable(), setDesignable(), setScriptable(), setStored()
+*/
+void QMetaPropertyBuilder::setEditable(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Editable, value);
+}
+
+/*!
+ Sets the \c USER flag on this property to \a value.
+
+ \sa isUser(), setDesignable(), setScriptable()
+*/
+void QMetaPropertyBuilder::setUser(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(User, value);
+}
+
+/*!
+ Sets the C++ setter flag on this property to \a value, which is
+ true if the property has a C++ setter function that follows Qt's
+ standard "name" / "setName" pattern.
+
+ \sa hasStdCppSet()
+*/
+void QMetaPropertyBuilder::setStdCppSet(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(StdCppSet, value);
+}
+
+/*!
+ Sets this property to be of an enumerator or flag type if
+ \a value is true.
+
+ \sa isEnumOrFlag()
+*/
+void QMetaPropertyBuilder::setEnumOrFlag(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(EnumOrFlag, value);
+}
+
+/*!
+ Sets the \c CONSTANT flag on this property to \a value.
+
+ \sa isConstant()
+*/
+void QMetaPropertyBuilder::setConstant(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Constant, value);
+}
+
+/*!
+ Sets the \c FINAL flag on this property to \a value.
+
+ \sa isFinal()
+*/
+void QMetaPropertyBuilder::setFinal(bool value)
+{
+ QMetaPropertyBuilderPrivate *d = d_func();
+ if (d)
+ d->setFlag(Final, value);
+}
+
+
+/*!
+ \class QMetaEnumBuilder
+ \internal
+ \brief The QMetaEnumBuilder class enables modifications to an enumerator definition on a meta object builder.
+*/
+
+QMetaEnumBuilderPrivate *QMetaEnumBuilder::d_func() const
+{
+ if (_mobj && _index >= 0 && _index < _mobj->d->enumerators.size())
+ return &(_mobj->d->enumerators[_index]);
+ else
+ return 0;
+}
+
+/*!
+ \fn QMetaEnumBuilder::QMetaEnumBuilder()
+ \internal
+*/
+
+/*!
+ \fn int QMetaEnumBuilder::index() const
+
+ Returns the index of this enumerator within its QMetaObjectBuilder.
+*/
+
+/*!
+ Returns the name of the enumerator (without the scope).
+*/
+QByteArray QMetaEnumBuilder::name() const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ return d->name;
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns true if this enumerator is used as a flag; otherwise returns
+ false.
+
+ \sa setIsFlag()
+*/
+bool QMetaEnumBuilder::isFlag() const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ return d->isFlag;
+ else
+ return false;
+}
+
+/*!
+ Sets this enumerator to be used as a flag if \a value is true.
+
+ \sa isFlag()
+*/
+void QMetaEnumBuilder::setIsFlag(bool value)
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ d->isFlag = value;
+}
+
+/*!
+ Returns the number of keys.
+
+ \sa key(), addKey()
+*/
+int QMetaEnumBuilder::keyCount() const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d)
+ return d->keys.size();
+ else
+ return 0;
+}
+
+/*!
+ Returns the key with the given \a index, or an empty QByteArray
+ if no such key exists.
+
+ \sa keyCount(), addKey(), value()
+*/
+QByteArray QMetaEnumBuilder::key(int index) const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d && index >= 0 && index < d->keys.size())
+ return d->keys[index];
+ else
+ return QByteArray();
+}
+
+/*!
+ Returns the value with the given \a index; or returns -1 if there
+ is no such value.
+
+ \sa keyCount(), addKey(), key()
+*/
+int QMetaEnumBuilder::value(int index) const
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d && index >= 0 && index < d->keys.size())
+ return d->values[index];
+ else
+ return -1;
+}
+
+/*!
+ Adds a new key called \a name to this enumerator, associated
+ with \a value. Returns the index of the new key.
+
+ \sa keyCount(), key(), value(), removeKey()
+*/
+int QMetaEnumBuilder::addKey(const QByteArray& name, int value)
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d) {
+ int index = d->keys.size();
+ d->keys += name;
+ d->values += value;
+ return index;
+ } else {
+ return -1;
+ }
+}
+
+/*!
+ Removes the key at \a index from this enumerator.
+
+ \sa addKey()
+*/
+void QMetaEnumBuilder::removeKey(int index)
+{
+ QMetaEnumBuilderPrivate *d = d_func();
+ if (d && index >= 0 && index < d->keys.size()) {
+ d->keys.removeAt(index);
+ d->values.removeAt(index);
+ }
+}
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/qmetaobjectbuilder_p.h b/src/serviceframework/ipc/qmetaobjectbuilder_p.h
new file mode 100644
index 00000000..b123f2c9
--- /dev/null
+++ b/src/serviceframework/ipc/qmetaobjectbuilder_p.h
@@ -0,0 +1,342 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMETAOBJECTBUILDER_H
+#define QMETAOBJECTBUILDER_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of moc. This header file may change from version to version without notice,
+// or even be removed.
+//
+// We mean it.
+//
+
+#include <qserviceframeworkglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qmap.h>
+
+QTM_BEGIN_NAMESPACE
+
+class QMetaObjectBuilderPrivate;
+class QMetaMethodBuilder;
+class QMetaMethodBuilderPrivate;
+class QMetaPropertyBuilder;
+class QMetaPropertyBuilderPrivate;
+class QMetaEnumBuilder;
+class QMetaEnumBuilderPrivate;
+
+typedef const QMetaObject& (*QMetaObjectAccessor)();
+
+#ifdef IGNORE_METAOBJECTBUILDER_EXPORT
+ class QMetaObjectBuilder
+#else
+ class Q_AUTOTEST_EXPORT QMetaObjectBuilder
+#endif
+{
+public:
+ enum AddMember
+ {
+ ClassName = 0x00000001,
+ SuperClass = 0x00000002,
+ Methods = 0x00000004,
+ Signals = 0x00000008,
+ Slots = 0x00000010,
+ Constructors = 0x00000020,
+ Properties = 0x00000040,
+ Enumerators = 0x00000080,
+ ClassInfos = 0x00000100,
+ RelatedMetaObjects = 0x00000200,
+ StaticMetacall = 0x00000400,
+ PublicMethods = 0x00000800,
+ ProtectedMethods = 0x00001000,
+ PrivateMethods = 0x00002000,
+ AllMembers = 0x7FFFFFFF,
+ AllPrimaryMembers = 0x7FFFFBFC
+ };
+ Q_DECLARE_FLAGS(AddMembers, AddMember)
+
+ enum MetaObjectFlag {
+ DynamicMetaObject = 0x01
+ };
+ Q_DECLARE_FLAGS(MetaObjectFlags, MetaObjectFlag)
+
+ QMetaObjectBuilder();
+ explicit QMetaObjectBuilder(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers);
+ virtual ~QMetaObjectBuilder();
+
+ QByteArray className() const;
+ void setClassName(const QByteArray& name);
+
+ const QMetaObject *superClass() const;
+ void setSuperClass(const QMetaObject *meta);
+
+ MetaObjectFlags flags() const;
+ void setFlags(MetaObjectFlags);
+
+ int methodCount() const;
+ int constructorCount() const;
+ int propertyCount() const;
+ int enumeratorCount() const;
+ int classInfoCount() const;
+ int relatedMetaObjectCount() const;
+
+ QMetaMethodBuilder addMethod(const QByteArray& signature);
+ QMetaMethodBuilder addMethod(const QByteArray& signature, const QByteArray& returnType);
+ QMetaMethodBuilder addMethod(const QMetaMethod& prototype);
+
+ QMetaMethodBuilder addSlot(const QByteArray& signature);
+ QMetaMethodBuilder addSignal(const QByteArray& signature);
+
+ QMetaMethodBuilder addConstructor(const QByteArray& signature);
+ QMetaMethodBuilder addConstructor(const QMetaMethod& prototype);
+
+ QMetaPropertyBuilder addProperty(const QByteArray& name, const QByteArray& type, int notifierId=-1);
+ QMetaPropertyBuilder addProperty(const QMetaProperty& prototype);
+
+ QMetaEnumBuilder addEnumerator(const QByteArray& name);
+ QMetaEnumBuilder addEnumerator(const QMetaEnum& prototype);
+
+ int addClassInfo(const QByteArray& name, const QByteArray& value);
+
+#ifdef Q_NO_DATA_RELOCATION
+ int addRelatedMetaObject(const QMetaObjectAccessor &meta);
+#else
+ int addRelatedMetaObject(const QMetaObject *meta);
+#endif
+
+ void addMetaObject(const QMetaObject *prototype, QMetaObjectBuilder::AddMembers members = AllMembers);
+
+ QMetaMethodBuilder method(int index) const;
+ QMetaMethodBuilder constructor(int index) const;
+ QMetaPropertyBuilder property(int index) const;
+ QMetaEnumBuilder enumerator(int index) const;
+ const QMetaObject *relatedMetaObject(int index) const;
+
+ QByteArray classInfoName(int index) const;
+ QByteArray classInfoValue(int index) const;
+
+ void removeMethod(int index);
+ void removeConstructor(int index);
+ void removeProperty(int index);
+ void removeEnumerator(int index);
+ void removeClassInfo(int index);
+ void removeRelatedMetaObject(int index);
+
+ int indexOfMethod(const QByteArray& signature);
+ int indexOfSignal(const QByteArray& signature);
+ int indexOfSlot(const QByteArray& signature);
+ int indexOfConstructor(const QByteArray& signature);
+ int indexOfProperty(const QByteArray& name);
+ int indexOfEnumerator(const QByteArray& name);
+ int indexOfClassInfo(const QByteArray& name);
+
+ typedef QMetaObjectExtraData::StaticMetacallFunction StaticMetacallFunction;
+
+ QMetaObjectBuilder::StaticMetacallFunction staticMetacallFunction() const;
+ void setStaticMetacallFunction(QMetaObjectBuilder::StaticMetacallFunction value);
+
+ QMetaObject *toMetaObject() const;
+ QByteArray toRelocatableData(bool * = 0) const;
+ static void fromRelocatableData(QMetaObject *, const QMetaObject *, const QByteArray &);
+
+#ifndef QT_NO_DATASTREAM
+ void serialize(QDataStream& stream) const;
+ void deserialize
+ (QDataStream& stream,
+ const QMap<QByteArray, const QMetaObject *>& references);
+#endif
+
+private:
+ Q_DISABLE_COPY(QMetaObjectBuilder)
+
+ QMetaObjectBuilderPrivate *d;
+
+ friend class QMetaMethodBuilder;
+ friend class QMetaPropertyBuilder;
+ friend class QMetaEnumBuilder;
+};
+
+#ifdef IGNORE_METAOBJECTBUILDER_EXPORT
+ class QMetaMethodBuilder
+#else
+ class Q_AUTOTEST_EXPORT QMetaMethodBuilder
+#endif
+{
+public:
+ QMetaMethodBuilder() : _mobj(0), _index(0) {}
+
+ int index() const;
+
+ QMetaMethod::MethodType methodType() const;
+ QByteArray signature() const;
+
+ QByteArray returnType() const;
+ void setReturnType(const QByteArray& value);
+
+ QList<QByteArray> parameterNames() const;
+ void setParameterNames(const QList<QByteArray>& value);
+
+ QByteArray tag() const;
+ void setTag(const QByteArray& value);
+
+ QMetaMethod::Access access() const;
+ void setAccess(QMetaMethod::Access value);
+
+ int attributes() const;
+ void setAttributes(int value);
+
+private:
+ const QMetaObjectBuilder *_mobj;
+ int _index;
+
+ friend class QMetaObjectBuilder;
+ friend class QMetaPropertyBuilder;
+
+ QMetaMethodBuilder(const QMetaObjectBuilder *mobj, int index)
+ : _mobj(mobj), _index(index) {}
+
+ QMetaMethodBuilderPrivate *d_func() const;
+};
+
+#ifdef IGNORE_METAOBJECTBUILDER_EXPORT
+ class QMetaPropertyBuilder
+#else
+ class Q_AUTOTEST_EXPORT QMetaPropertyBuilder
+#endif
+{
+public:
+ QMetaPropertyBuilder() : _mobj(0), _index(0) {}
+
+ int index() const { return _index; }
+
+ QByteArray name() const;
+ QByteArray type() const;
+
+ bool hasNotifySignal() const;
+ QMetaMethodBuilder notifySignal() const;
+ void setNotifySignal(const QMetaMethodBuilder& value);
+ void removeNotifySignal();
+
+ bool isReadable() const;
+ bool isWritable() const;
+ bool isResettable() const;
+ bool isDesignable() const;
+ bool isScriptable() const;
+ bool isStored() const;
+ bool isEditable() const;
+ bool isUser() const;
+ bool hasStdCppSet() const;
+ bool isEnumOrFlag() const;
+ bool isConstant() const;
+ bool isFinal() const;
+
+ void setReadable(bool value);
+ void setWritable(bool value);
+ void setResettable(bool value);
+ void setDesignable(bool value);
+ void setScriptable(bool value);
+ void setStored(bool value);
+ void setEditable(bool value);
+ void setUser(bool value);
+ void setStdCppSet(bool value);
+ void setEnumOrFlag(bool value);
+ void setConstant(bool value);
+ void setFinal(bool value);
+
+private:
+ const QMetaObjectBuilder *_mobj;
+ int _index;
+
+ friend class QMetaObjectBuilder;
+
+ QMetaPropertyBuilder(const QMetaObjectBuilder *mobj, int index)
+ : _mobj(mobj), _index(index) {}
+
+ QMetaPropertyBuilderPrivate *d_func() const;
+};
+
+#ifdef IGNORE_METAOBJECTBUILDER_EXPORT
+ class QMetaEnumBuilder
+#else
+ class Q_AUTOTEST_EXPORT QMetaEnumBuilder
+#endif
+{
+public:
+ QMetaEnumBuilder() : _mobj(0), _index(0) {}
+
+ int index() const { return _index; }
+
+ QByteArray name() const;
+
+ bool isFlag() const;
+ void setIsFlag(bool value);
+
+ int keyCount() const;
+ QByteArray key(int index) const;
+ int value(int index) const;
+
+ int addKey(const QByteArray& name, int value);
+ void removeKey(int index);
+
+private:
+ const QMetaObjectBuilder *_mobj;
+ int _index;
+
+ friend class QMetaObjectBuilder;
+
+ QMetaEnumBuilder(const QMetaObjectBuilder *mobj, int index)
+ : _mobj(mobj), _index(index) {}
+
+ QMetaEnumBuilderPrivate *d_func() const;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::AddMembers)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaObjectBuilder::MetaObjectFlags)
+
+QTM_END_NAMESPACE
+
+#endif
diff --git a/src/serviceframework/ipc/qremoteserviceregister_dbus_p.cpp b/src/serviceframework/ipc/qremoteserviceregister_dbus_p.cpp
new file mode 100644
index 00000000..3097a3e3
--- /dev/null
+++ b/src/serviceframework/ipc/qremoteserviceregister_dbus_p.cpp
@@ -0,0 +1,359 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteserviceregister_p.h"
+#include "qremoteserviceregister_dbus_p.h"
+
+#include <QDataStream>
+#include <QTimer>
+
+
+QTM_BEGIN_NAMESPACE
+
+class DBusEndPoint : public QServiceIpcEndPoint
+{
+ Q_OBJECT
+
+public:
+ DBusEndPoint(QDBusInterface* iface, int type, QObject* parent = 0)
+ : QServiceIpcEndPoint(parent), interface(iface), endType(type)
+ {
+ Q_ASSERT(interface);
+ interface->setParent(this);
+ connect(interface, SIGNAL(packageReceived(QByteArray,int,QString)),
+ this, SLOT(readPackage(QByteArray,int,QString)));
+
+ if (endType == CLIENT) {
+ QDBusServiceWatcher *watcher = new QDBusServiceWatcher(interface->service(),
+ interface->connection(),
+ QDBusServiceWatcher::WatchForUnregistration);
+
+ QObject::connect(watcher, SIGNAL(serviceUnregistered(QString)),
+ this, SLOT(serviceRemoved(QString)));
+ }
+ }
+
+ ~DBusEndPoint()
+ {
+ }
+
+public slots:
+ void closeIncoming()
+ {
+ QDBusMessage msg = interface->callWithArgumentList(QDBus::AutoDetect, QLatin1String("closeIncoming"),
+ QList<QVariant>() << instanceId);
+ }
+
+ void setInstanceId(const QString& id)
+ {
+ instanceId = id;
+ }
+
+Q_SIGNALS:
+ void ipcFault(QService::UnrecoverableIPCError);
+
+protected:
+ void flushPackage(const QServicePackage& package)
+ {
+ if (!QDBusConnection::sessionBus().isConnected()) {
+ qWarning() << "Cannot connect to DBus";
+ }
+
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_6);
+ out << package;
+
+ packageId = package.d->messageId;
+ interface->asyncCall(QLatin1String("writePackage"), block, endType, packageId);
+ }
+
+protected slots:
+ void readPackage(const QByteArray &package, int type, const QString &id) {
+ // Check that its of a client-server nature
+ if (endType != type) {
+ // Client to Server
+ if (type != SERVER) {
+ readIncoming(package);
+ } else {
+ // Server to Client
+ if (id == packageId) {
+ readIncoming(package);
+ }
+ }
+ }
+ }
+
+ void readIncoming(const QByteArray &package)
+ {
+ QDataStream data(package);
+ QServicePackage pack;
+ data >> pack;
+
+ incoming.enqueue(pack);
+ emit readyRead();
+ }
+
+ void serviceRemoved(const QString& name)
+ {
+ Q_UNUSED(name);
+ QString serviceName = interface->service();
+ QDBusReply<bool> reply = interface->connection().interface()->isServiceRegistered(serviceName);
+ if (!reply.value()) {
+ emit ipcFault(QService::ErrorServiceNoLongerAvailable);
+ }
+ }
+
+private:
+ QDBusInterface* interface;
+ QString packageId;
+ int endType;
+ QString instanceId;
+};
+
+class DBusSessionAdaptor: public QDBusAbstractAdaptor
+{
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "com.nokia.qtmobility.sfw.DBusSession")
+
+public:
+ DBusSessionAdaptor(QObject *parent);
+ ~DBusSessionAdaptor() {}
+
+public slots:
+ QByteArray writePackage(const QByteArray &package, int type, const QString &id) {
+ QByteArray ret;
+ QMetaObject::invokeMethod(parent(), "writePackage",
+ Q_RETURN_ARG(QByteArray, ret),
+ Q_ARG(QByteArray, package),
+ Q_ARG(int, type),
+ Q_ARG(QString, id));
+ return ret;
+ }
+
+ bool processIncoming() {
+ bool ret;
+ QMetaObject::invokeMethod(parent(), "processIncoming",
+ Q_RETURN_ARG(bool, ret));
+ return ret;
+ }
+
+ void acceptIncoming(bool accept) {
+ QMetaObject::invokeMethod(parent(), "acceptIncoming",
+ Q_ARG(bool, accept));
+ }
+
+ void closeIncoming(const QString& instanceId) {
+ QMetaObject::invokeMethod(parent(), "closeIncoming",
+ Q_ARG(QString, instanceId));
+ }
+
+signals:
+ void packageReceived(const QByteArray &package, int type, const QString &id);
+ void newConnection(int pid, int uid);
+};
+
+DBusSessionAdaptor::DBusSessionAdaptor(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+{
+ setAutoRelaySignals(true);
+}
+
+QRemoteServiceRegisterDBusPrivate::QRemoteServiceRegisterDBusPrivate(QObject* parent)
+ : QRemoteServiceRegisterPrivate(parent)
+{
+}
+
+QRemoteServiceRegisterDBusPrivate::~QRemoteServiceRegisterDBusPrivate()
+{
+}
+
+void QRemoteServiceRegisterDBusPrivate::publishServices(const QString& ident)
+{
+ if (!createServiceEndPoint(ident))
+ QTimer::singleShot(0, QCoreApplication::instance(), SLOT(quit()));
+}
+
+/*!
+ Creates endpoint on service side.
+*/
+bool QRemoteServiceRegisterDBusPrivate::createServiceEndPoint(const QString& ident)
+{
+ int endPoints = 0;
+
+ InstanceManager *iManager = InstanceManager::instance();
+ QList<QRemoteServiceRegister::Entry> list = iManager->allEntries();
+
+ if (list.size() < 1)
+ return false;
+
+ QDBusConnection connection = QDBusConnection::sessionBus();
+ if (!connection.isConnected()) {
+ qWarning() << "Cannot connect to DBus";
+ return 0;
+ }
+
+ // Registers the service and session object on DBus if needed
+ for (int i=0; i<list.size(); i++) {
+ QString serviceName = "com.nokia.qtmobility.sfw." + list[i].serviceName();
+ QDBusReply<bool> reply = connection.interface()->isServiceRegistered(serviceName);
+ if (reply.value())
+ continue;
+
+ if (!connection.registerService(serviceName)) {
+ qWarning() << "Cannot register service to DBus:" << serviceName;
+ continue;
+ }
+
+ // Create and register our DBusSession server/client
+ session = new DBusSession(this);
+ new DBusSessionAdaptor(session);
+ QObject::connect(session, SIGNAL(newConnection(int,int)),
+ this, SLOT(processIncoming(int,int)));
+
+ QString path = "/" + list[i].interfaceName() + "/" + ident;
+ path.replace(QLatin1String("."), QLatin1String("/"));
+ if (!connection.objectRegisteredAt(path)) {
+ if (!connection.registerObject(path, session)) {
+ qWarning() << "Cannot register service session to DBus:" << path;
+ continue;
+ }
+
+ iface = new QDBusInterface(serviceName, path, QLatin1String(""), QDBusConnection::sessionBus());
+ if (!iface->isValid()) {
+ qWarning() << "Cannot connect to remote service" << serviceName << path;;
+ continue;
+ }
+
+ DBusEndPoint* ipcEndPoint = new DBusEndPoint(iface, SERVER);
+ ObjectEndPoint* endPoint = new ObjectEndPoint(ObjectEndPoint::Service, ipcEndPoint, this);
+
+ // Connect session process disconnections
+ QObject::connect(session, SIGNAL(closeConnection(QString,QString)),
+ endPoint, SLOT(disconnected(QString,QString)));
+
+ endPoints++;
+ }
+ }
+
+ if (endPoints > 0)
+ return true;
+
+ return false;
+}
+
+void QRemoteServiceRegisterDBusPrivate::processIncoming(int pid, int uid)
+{
+ if (getSecurityFilter()) {
+ QRemoteServiceRegisterCredentials cred;
+ cred.fd = -1;
+ cred.pid = pid;
+ cred.uid = uid;
+ cred.gid = -1;
+
+ if (!getSecurityFilter()(reinterpret_cast<const void *>(&cred))) {
+ session->acceptIncoming(false);
+
+ // Close service if no instances
+ if (quitOnLastInstanceClosed() &&
+ InstanceManager::instance()->totalInstances() < 1)
+ QCoreApplication::exit();
+
+ return;
+ }
+ }
+
+ session->acceptIncoming(true);
+}
+
+QRemoteServiceRegisterPrivate* QRemoteServiceRegisterPrivate::constructPrivateObject(QObject *parent)
+{
+ return new QRemoteServiceRegisterDBusPrivate(parent);
+}
+
+/*!
+ Creates endpoint on client side.
+*/
+QObject* QRemoteServiceRegisterPrivate::proxyForService(const QRemoteServiceRegister::Entry& entry, const QString& location)
+{
+ const QString serviceName = "com.nokia.qtmobility.sfw." + entry.serviceName();
+ QString path = "/" + entry.interfaceName() + "/" + location;
+ path.replace(QLatin1String("."), QLatin1String("/"));
+
+ QDBusConnection connection = QDBusConnection::sessionBus();
+ if (!connection.isConnected()) {
+ qWarning() << "Cannot connect to DBus";
+ return 0;
+ }
+
+ // Dummy call to autostart the service if not running
+ connection.call(QDBusMessage::createMethodCall(serviceName, path, QLatin1String(""), QLatin1String("q_autostart")));
+
+ QDBusInterface *iface = new QDBusInterface(serviceName, path, QLatin1String(""), QDBusConnection::sessionBus());
+ if (!iface->isValid()) {
+ qWarning() << "Cannot connect to remote service" << serviceName << path;
+ return 0;
+ }
+
+ QDBusReply<bool> reply = iface->call(QDBus::Block, QLatin1String("processIncoming"));
+ if (reply.value()) {
+ DBusEndPoint* ipcEndPoint = new DBusEndPoint(iface, CLIENT);
+ ObjectEndPoint* endPoint = new ObjectEndPoint(ObjectEndPoint::Client, ipcEndPoint);
+
+ QObject *proxy = endPoint->constructProxy(entry);
+ ipcEndPoint->setInstanceId(endPoint->getInstanceId());
+
+ if (proxy) {
+ QObject::connect(proxy, SIGNAL(destroyed()), endPoint, SLOT(deleteLater()));
+ QObject::connect(proxy, SIGNAL(destroyed()), ipcEndPoint, SLOT(closeIncoming()));
+ QObject::connect(ipcEndPoint, SIGNAL(ipcFault(QService::UnrecoverableIPCError)),
+ proxy, SIGNAL(errorUnrecoverableIPCFault(QService::UnrecoverableIPCError)));
+ }
+ return proxy;
+ }
+
+ qDebug() << "Insufficient credentials to load a service instance";
+ return 0;
+}
+
+#include "moc_qremoteserviceregister_dbus_p.cpp"
+#include "qremoteserviceregister_dbus_p.moc"
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/qremoteserviceregister_dbus_p.h b/src/serviceframework/ipc/qremoteserviceregister_dbus_p.h
new file mode 100644
index 00000000..50e88139
--- /dev/null
+++ b/src/serviceframework/ipc/qremoteserviceregister_dbus_p.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTESERVICEREGISTER_DBUS_P_H
+#define QREMOTESERVICEREGISTER_DBUS_P_H
+
+#include <QUuid>
+#include <QtDBus/QtDBus>
+
+#include "qremoteserviceregister.h"
+#include "instancemanager_p.h"
+#include "qserviceinterfacedescriptor.h"
+#include "ipcendpoint_p.h"
+#include "objectendpoint_dbus_p.h"
+
+QTM_BEGIN_NAMESPACE
+
+#define SERVER 0
+#define CLIENT 1
+
+class ObjectEndPoint;
+
+class DBusSession: public QObject, protected QDBusContext
+{
+ Q_OBJECT
+public:
+ DBusSession(QObject* parent = 0)
+ : QObject(parent)
+ {}
+ ~DBusSession() {}
+
+public slots:
+ QByteArray writePackage(const QByteArray &package, int type, const QString &id) {
+
+ QDataStream data(package);
+ QServicePackage pack;
+ data >> pack;
+
+ if (type == CLIENT && pack.d->packageType == 0) {
+ // Use the client DBus connection as the Id
+ QDBusReply<QString> reply =
+ connection().interface()->serviceOwner(message().service());
+ QString clientId = reply.value();
+ pack.d->payload = QVariant(clientId);
+
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_6);
+ out << pack;
+
+ emit packageReceived(block, type, id);
+ return block;
+ }
+
+ emit packageReceived(package, type, id);
+ return package;
+ }
+
+ bool processIncoming() {
+ int pid = connection().interface()->servicePid(message().service());
+ int uid = connection().interface()->serviceUid(message().service());
+ emit newConnection(pid, uid);
+ return m_accept;
+ }
+
+ void acceptIncoming(bool accept) {
+ m_accept = accept;
+ }
+
+ void closeIncoming(const QString& instanceId) {
+ QDBusReply<QString> reply =
+ connection().interface()->serviceOwner(message().service());
+ const QString& clientId = reply.value();
+ emit closeConnection(clientId, instanceId);
+ }
+
+Q_SIGNALS:
+ void packageReceived(const QByteArray &package, int type, const QString &id);
+ void newConnection(int pid, int uid);
+ void closeConnection(const QString& clientId, const QString& instanceId);
+
+private:
+ bool m_accept;
+};
+
+
+class QRemoteServiceRegisterDBusPrivate: public QRemoteServiceRegisterPrivate
+{
+ Q_OBJECT
+public:
+ QRemoteServiceRegisterDBusPrivate(QObject* parent);
+ ~QRemoteServiceRegisterDBusPrivate();
+ void publishServices(const QString& ident );
+
+public slots:
+ void processIncoming(int pid, int uid);
+
+private:
+ bool createServiceEndPoint(const QString& ident);
+
+ QList<ObjectEndPoint*> pendingConnections;
+ QDBusInterface *iface;
+ DBusSession *session;
+ QDBusConnection *connection;
+};
+
+QTM_END_NAMESPACE
+
+#endif
diff --git a/src/serviceframework/ipc/qremoteserviceregister_ls_p.cpp b/src/serviceframework/ipc/qremoteserviceregister_ls_p.cpp
new file mode 100644
index 00000000..6af7d344
--- /dev/null
+++ b/src/serviceframework/ipc/qremoteserviceregister_ls_p.cpp
@@ -0,0 +1,286 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteserviceregister_p.h"
+#include "qremoteserviceregister_ls_p.h"
+#include "ipcendpoint_p.h"
+#include "objectendpoint_p.h"
+
+#include <QLocalServer>
+#include <QLocalSocket>
+#include <QDataStream>
+#include <QTimer>
+#include <QProcess>
+#include <QFile>
+
+#include <time.h>
+#include <sys/types.h> /* See NOTES */
+
+#ifndef Q_OS_WIN
+#include <sys/un.h>
+#include <sys/socket.h>
+#else
+// Needed for ::Sleep, while we wait for a better solution
+#include <Windows.h>
+#include <Winbase.h>
+#endif
+
+#ifdef LOCAL_PEERCRED /* from sys/un.h */
+#include <sys/ucred.h>
+#endif
+
+QTM_BEGIN_NAMESPACE
+
+//IPC based on QLocalSocket
+
+class LocalSocketEndPoint : public QServiceIpcEndPoint
+{
+ Q_OBJECT
+public:
+ LocalSocketEndPoint(QLocalSocket* s, QObject* parent = 0)
+ : QServiceIpcEndPoint(parent), socket(s)
+ {
+ Q_ASSERT(socket);
+ socket->setParent(this);
+ connect(s, SIGNAL(readyRead()), this, SLOT(readIncoming()));
+ connect(s, SIGNAL(disconnected()), this, SIGNAL(disconnected()));
+ connect(s, SIGNAL(disconnected()), this, SLOT(ipcfault()));
+
+ if (socket->bytesAvailable())
+ QTimer::singleShot(0, this, SLOT(readIncoming()));
+ }
+
+ ~LocalSocketEndPoint()
+ {
+ disconnect(this, SLOT(ipcfault()));
+ socket->close();
+ }
+
+Q_SIGNALS:
+ void errorUnrecoverableIPCFault(QService::UnrecoverableIPCError);
+
+
+protected:
+ void flushPackage(const QServicePackage& package)
+ {
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_6);
+ out << package;
+ socket->write(block);
+ }
+
+protected slots:
+ void readIncoming()
+ {
+ QDataStream in(socket);
+ in.setVersion(QDataStream::Qt_4_6);
+
+ while (socket->bytesAvailable()) {
+ QServicePackage package;
+ in >> package;
+ incoming.enqueue(package);
+ }
+
+ emit readyRead();
+ }
+ void ipcfault()
+ {
+ emit errorUnrecoverableIPCFault(QService::ErrorServiceNoLongerAvailable);
+ }
+
+private:
+ QLocalSocket* socket;
+};
+
+QRemoteServiceRegisterLocalSocketPrivate::QRemoteServiceRegisterLocalSocketPrivate(QObject* parent)
+ : QRemoteServiceRegisterPrivate(parent)
+{
+}
+
+void QRemoteServiceRegisterLocalSocketPrivate::publishServices( const QString& ident)
+{
+ createServiceEndPoint(ident) ;
+}
+
+void QRemoteServiceRegisterLocalSocketPrivate::processIncoming()
+{
+ if (localServer->hasPendingConnections()) {
+ QLocalSocket* s = localServer->nextPendingConnection();
+ //LocalSocketEndPoint owns socket
+ int fd = s->socketDescriptor();
+ if (getSecurityFilter()){
+ QRemoteServiceRegisterCredentials qcred;
+ memset(&qcred, 0, sizeof(QRemoteServiceRegisterCredentials));
+ qcred.fd = fd;
+
+#if defined(LOCAL_PEERCRED)
+ struct xucred xuc;
+ socklen_t len = sizeof(struct xucred);
+
+ if (getsockopt(fd, SOL_SOCKET, LOCAL_PEERCRED, &xuc, &len) == 0) {
+ qcred.pid = -1; // No PID on bsd
+ qcred.uid = xuc.cr_uid;
+ qcred.gid = xuc.cr_gid;
+
+ }
+
+#elif defined(SO_PEERCRED)
+ struct ucred uc;
+ socklen_t len = sizeof(struct ucred);
+
+ if( getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &uc, &len) == 0) {
+ qcred.pid = uc.pid;
+ qcred.uid = uc.uid;
+ qcred.gid = uc.gid;
+ }
+ else {
+ s->close();
+ perror("Failed to get peer credential");
+ return;
+ }
+#else
+ s->close();
+ qWarning("Credentials check unsupprted on this platform");
+ return;
+#endif
+ qDebug() << "Security filter call";
+ if (!getSecurityFilter()(reinterpret_cast<const void *>(&qcred))){
+ s->close();
+ return;
+ }
+ }
+ LocalSocketEndPoint* ipcEndPoint = new LocalSocketEndPoint(s);
+ ObjectEndPoint* endpoint = new ObjectEndPoint(ObjectEndPoint::Service, ipcEndPoint, this);
+ Q_UNUSED(endpoint);
+ }
+}
+
+/*
+ Creates endpoint on service side.
+*/
+bool QRemoteServiceRegisterLocalSocketPrivate::createServiceEndPoint(const QString& ident)
+{
+ //other IPC mechanisms such as dbus may have to publish the
+ //meta object definition for all registered service types
+ QLocalServer::removeServer(ident);
+ localServer = new QLocalServer(this);
+ if ( !localServer->listen(ident) ) {
+ qWarning() << "Cannot create local socket endpoint";
+ return false;
+ }
+ connect(localServer, SIGNAL(newConnection()), this, SLOT(processIncoming()));
+ if (localServer->hasPendingConnections())
+ QTimer::singleShot(0, this, SLOT(processIncoming()));
+
+ return true;
+}
+
+QRemoteServiceRegisterPrivate* QRemoteServiceRegisterPrivate::constructPrivateObject(QObject *parent)
+{
+ return new QRemoteServiceRegisterLocalSocketPrivate(parent);
+}
+
+/*
+ Creates endpoint on client side.
+*/
+QObject* QRemoteServiceRegisterPrivate::proxyForService(const QRemoteServiceRegister::Entry& entry, const QString& location)
+{
+ QLocalSocket* socket = new QLocalSocket();
+ socket->connectToServer(location);
+ if (!socket->waitForConnected()){
+ if (!socket->isValid()) {
+ QString path = location;
+ qWarning() << "Cannot connect to remote service, trying to start service " << path;
+ // If we have autotests enable, check for the service in .
+#ifdef QTM_BUILD_UNITTESTS
+ QFile file("./" + path);
+ if (file.exists()){
+ path.prepend("./");
+ }
+#endif
+ qint64 pid = 0;
+ // Start the service as a detached process
+ if (QProcess::startDetached(path, QStringList(), QString(), &pid)){
+ int i;
+ socket->connectToServer(location);
+ for (i = 0; !socket->isValid() && i < 1000; i++){
+ // Temporary hack till we can improve startup signaling
+#ifdef Q_OS_WIN
+ ::Sleep(10);
+#else
+ struct timespec tm;
+ tm.tv_sec = 0;
+ tm.tv_nsec = 1000000;
+ nanosleep(&tm, 0x0);
+#endif
+ socket->connectToServer(location);
+ // keep trying for a while
+ }
+ if (!socket->isValid()){
+ qWarning() << "Server failed to start within waiting period";
+ return false;
+ }
+ }
+ else
+ qWarning() << "Server could not be started";
+ }
+ }
+ if (socket->isValid()){
+ LocalSocketEndPoint* ipcEndPoint = new LocalSocketEndPoint(socket);
+ ObjectEndPoint* endPoint = new ObjectEndPoint(ObjectEndPoint::Client, ipcEndPoint);
+
+ QObject *proxy = endPoint->constructProxy(entry);
+ if (proxy){
+ QObject::connect(proxy, SIGNAL(destroyed()), endPoint, SLOT(deleteLater()));
+ QObject::connect(ipcEndPoint, SIGNAL(errorUnrecoverableIPCFault(QService::UnrecoverableIPCError)),
+ proxy, SIGNAL(errorUnrecoverableIPCFault(QService::UnrecoverableIPCError)));
+ }
+ ipcEndPoint->setParent(proxy);
+ endPoint->setParent(proxy);
+ return proxy;
+ }
+ return 0;
+}
+
+#include "moc_qremoteserviceregister_ls_p.cpp"
+#include "qremoteserviceregister_ls_p.moc"
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/qremoteserviceregister_ls_p.h b/src/serviceframework/ipc/qremoteserviceregister_ls_p.h
new file mode 100644
index 00000000..356df496
--- /dev/null
+++ b/src/serviceframework/ipc/qremoteserviceregister_ls_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTESERVICEREGISTER_LS_P_H
+#define QREMOTESERVICEREGISTER_LS_P_H
+
+#include "qremoteserviceregister.h"
+#include "instancemanager_p.h"
+#include "qserviceinterfacedescriptor.h"
+#include "qremoteserviceregister_p.h"
+#include <QLocalServer>
+
+QTM_BEGIN_NAMESPACE
+
+class ObjectEndPoint;
+
+class QRemoteServiceRegisterLocalSocketPrivate: public QRemoteServiceRegisterPrivate
+{
+ Q_OBJECT
+public:
+ QRemoteServiceRegisterLocalSocketPrivate(QObject* parent);
+ void publishServices(const QString& ident );
+
+public slots:
+ void processIncoming();
+
+private:
+ bool createServiceEndPoint(const QString& ident);
+
+ QLocalServer* localServer;
+ QList<ObjectEndPoint*> pendingConnections;
+};
+
+QTM_END_NAMESPACE
+
+#endif
diff --git a/src/serviceframework/ipc/qremoteserviceregister_p.cpp b/src/serviceframework/ipc/qremoteserviceregister_p.cpp
new file mode 100644
index 00000000..a4b5b196
--- /dev/null
+++ b/src/serviceframework/ipc/qremoteserviceregister_p.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteserviceregister_p.h"
+#include "instancemanager_p.h"
+
+#include <QCoreApplication>
+
+QTM_BEGIN_NAMESPACE
+
+QRemoteServiceRegisterPrivate::QRemoteServiceRegisterPrivate(QObject* parent)
+ : QObject(parent), iFilter(0)
+{
+ setQuitOnLastInstanceClosed(true);
+}
+
+QRemoteServiceRegisterPrivate::~QRemoteServiceRegisterPrivate()
+{
+}
+
+//void QRemoteServiceRegisterPrivate::publishServices( const QString& ident)
+//{
+// qWarning("QRemoteServiceregisterPrivate::publishServices has not been reimplemented");
+//}
+//
+//void QRemoteServiceRegisterPrivate::processIncoming()
+//{
+// qWarning("QRemoteServiceRegisterPrivate::processIncoming has not been reimplemented");
+//}
+
+bool QRemoteServiceRegisterPrivate::quitOnLastInstanceClosed() const
+{
+ return m_quit;
+}
+
+void QRemoteServiceRegisterPrivate::setQuitOnLastInstanceClosed(bool quit)
+{
+ m_quit = quit;
+ if (m_quit) {
+ connect(InstanceManager::instance(), SIGNAL(allInstancesClosed()), QCoreApplication::instance(), SLOT(quit()));
+ }
+ else {
+ disconnect(InstanceManager::instance(), SIGNAL(allInstancesClosed()), QCoreApplication::instance(), SLOT(quit()));
+ }
+}
+
+QRemoteServiceRegister::SecurityFilter QRemoteServiceRegisterPrivate::setSecurityFilter(QRemoteServiceRegister::SecurityFilter filter)
+{
+ QRemoteServiceRegister::SecurityFilter f;
+ f = filter;
+ iFilter = filter;
+ return f;
+}
+
+QRemoteServiceRegister::SecurityFilter QRemoteServiceRegisterPrivate::getSecurityFilter()
+{
+ return iFilter;
+}
+
+
+#include "moc_qremoteserviceregister_p.cpp"
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/qremoteserviceregister_p.h b/src/serviceframework/ipc/qremoteserviceregister_p.h
new file mode 100644
index 00000000..0c7e493f
--- /dev/null
+++ b/src/serviceframework/ipc/qremoteserviceregister_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTESERVICEREGISTER_P_H
+#define QREMOTESERVICEREGISTER_P_H
+
+#include "qremoteserviceregister.h"
+#include "instancemanager_p.h"
+#include "qserviceinterfacedescriptor.h"
+
+QTM_BEGIN_NAMESPACE
+
+class ObjectEndPoint;
+class QRemoteServiceRegisterPrivate: public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool quitOnLastInstanceClosed READ quitOnLastInstanceClosed WRITE setQuitOnLastInstanceClosed)
+public:
+ QRemoteServiceRegisterPrivate(QObject* parent);
+ virtual ~QRemoteServiceRegisterPrivate();
+
+ virtual void publishServices(const QString& ident ) = 0;
+
+ virtual bool quitOnLastInstanceClosed() const;
+ virtual void setQuitOnLastInstanceClosed(const bool quit);
+
+ virtual QRemoteServiceRegister::SecurityFilter setSecurityFilter(QRemoteServiceRegister::SecurityFilter filter);
+
+public slots:
+ // Must be implemented in the subclass
+ //void processIncoming();
+
+protected:
+ virtual QRemoteServiceRegister::SecurityFilter getSecurityFilter();
+
+private:
+ bool m_quit;
+ QRemoteServiceRegister::SecurityFilter iFilter;
+
+public:
+ static QObject* proxyForService(const QRemoteServiceRegister::Entry& entry, const QString& location);
+ static QRemoteServiceRegisterPrivate* constructPrivateObject(QObject *parent);
+};
+
+QTM_END_NAMESPACE
+
+#endif
diff --git a/src/serviceframework/ipc/qremoteserviceregister_s60.cpp b/src/serviceframework/ipc/qremoteserviceregister_s60.cpp
new file mode 100644
index 00000000..969af3a3
--- /dev/null
+++ b/src/serviceframework/ipc/qremoteserviceregister_s60.cpp
@@ -0,0 +1,874 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteserviceregister_s60_p.h"
+#include "ipcendpoint_p.h"
+#include "objectendpoint_p.h"
+#include <QTimer>
+#include <QCoreApplication>
+
+#include <e32base.h>
+
+/* IPC based on Symbian Client-Server framework
+ * This module implements the Symbian specific IPC mechanisms and related control.
+ * IPC is based on Symbian Client-Server architecture.
+ */
+
+QTM_BEGIN_NAMESPACE
+
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+void printServicePackage(const QServicePackage& package)
+{
+ if(package.d) {
+ qDebug() << "QServicePackage packageType : " << package.d->packageType;
+ qDebug() << "QServicePackage QUuid : " << package.d->messageId;
+ qDebug() << "QServicePackage responseType : " << package.d->responseType;
+ qDebug() << "QServicePackage value : " << package.d->payload;
+ }
+ else {
+ qDebug() << "Invalid ServicePackage" << " LEAVING";
+ User::Leave(KErrCorrupt);
+ }
+}
+#endif
+
+
+class SymbianClientEndPoint: public QServiceIpcEndPoint
+{
+ Q_OBJECT
+public:
+ SymbianClientEndPoint(RServiceSession* session, QObject* parent = 0)
+ : QServiceIpcEndPoint(parent), session(session)
+ {
+ Q_ASSERT(session);
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "Symbian IPC endpoint created. 255 buffer";
+#endif
+ connect(session, SIGNAL(Disconnected()), this, SIGNAL(disconnected()));
+ }
+
+ ~SymbianClientEndPoint()
+ {
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "Symbian IPC client endpoint destroyed.";
+#endif
+ }
+
+ void PackageReceived(QServicePackage package)
+ {
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "SymbianClientEndPoint::PackageReceived. Enqueueing and emiting ReadyRead()";
+ printServicePackage(package);
+#endif
+ incoming.enqueue(package);
+ emit readyRead();
+ }
+
+protected:
+ void flushPackage(const QServicePackage& package)
+ {
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "SymbianClientEndPoint::flushPackage() for package: ";
+ printServicePackage(package);
+#endif
+ session->SendServicePackage(package);
+ }
+
+private:
+ RServiceSession *session;
+};
+
+class SymbianServerEndPoint: public QServiceIpcEndPoint
+{
+ Q_OBJECT
+public:
+ SymbianServerEndPoint(CServiceProviderServerSession* session, QObject* parent = 0)
+ : QServiceIpcEndPoint(parent), session(session), obj(0)
+ {
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "Symbian IPC server endpoint created.";
+#endif
+ Q_ASSERT(session);
+ // CBase derived classes cannot inherit from QObject,
+ // hence manual ownershipping instead of Qt hierarchy.
+ session->SetParent(this);
+ }
+
+
+ ~SymbianServerEndPoint()
+ {
+ #ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "Symbian IPC server endpoint destroyed. --- emit disconnected";
+ #endif
+
+ emit disconnected();
+ }
+
+ void packageReceived(QServicePackage package)
+ {
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "SymbianServerEndPoint::packageReceived, putting to queue and emiting readyread.";
+ printServicePackage(package);
+#endif
+ incoming.enqueue(package);
+ emit readyRead();
+ }
+
+ void setObjectEndPoint(ObjectEndPoint *aObj)
+ {
+ obj = aObj;
+ }
+
+protected:
+ void flushPackage(const QServicePackage& package)
+ {
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "SymbianServerEndPoint::flushPackage() for package: ";
+ printServicePackage(package);
+#endif
+ TRAPD(err, session->SendServicePackageL(package));
+ if(err != KErrNone){
+ qDebug() << "flushPackage: Failed to send request: " << err;
+ }
+ }
+
+private:
+ CServiceProviderServerSession *session;
+ ObjectEndPoint *obj;
+};
+
+QRemoteServiceRegisterSymbianPrivate::QRemoteServiceRegisterSymbianPrivate(QObject *parent)
+ : QRemoteServiceRegisterPrivate(parent), m_server(0)
+{
+}
+
+QRemoteServiceRegisterSymbianPrivate::~QRemoteServiceRegisterSymbianPrivate()
+{
+ delete m_server;
+}
+
+void QRemoteServiceRegisterSymbianPrivate::publishServices(const QString &ident)
+{
+ // Create service side of the Symbian Client-Server architecture.
+ m_server = new CServiceProviderServer(this);
+ TPtrC serviceIdent(reinterpret_cast<const TUint16*>(ident.utf16()));
+
+ if(getSecurityFilter())
+ m_server->setSecurityFilter(getSecurityFilter());
+
+ TInt err = m_server->Start(serviceIdent);
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ if (err != KErrNone) {
+ qDebug() << "publishServices: server->Start() failed: " << err;
+ } else {
+ qDebug("publishServices: service started successfully");
+ }
+#endif
+ // If we're started by the client, notify them we're running
+ RProcess::Rendezvous(KErrNone);
+}
+
+void QRemoteServiceRegisterSymbianPrivate::processIncoming(CServiceProviderServerSession* newSession)
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("processingIncoming session creation.");
+#endif
+ // Create service provider-side endpoints.
+ SymbianServerEndPoint* ipcEndPoint = new SymbianServerEndPoint(newSession, this);
+ ObjectEndPoint* endPoint = new ObjectEndPoint(ObjectEndPoint::Service, ipcEndPoint, this);
+ ipcEndPoint->setObjectEndPoint(endPoint);
+}
+
+QRemoteServiceRegister::SecurityFilter QRemoteServiceRegisterSymbianPrivate::setSecurityFilter(QRemoteServiceRegister::SecurityFilter filter)
+{
+ if(m_server)
+ m_server->setSecurityFilter(filter);
+
+ return QRemoteServiceRegisterPrivate::setSecurityFilter(filter);
+}
+
+
+QRemoteServiceRegisterPrivate* QRemoteServiceRegisterPrivate::constructPrivateObject(QObject *parent)
+{
+ return new QRemoteServiceRegisterSymbianPrivate(parent);
+}
+
+QObject* QRemoteServiceRegisterPrivate::proxyForService(const QRemoteServiceRegister::Entry &entry, const QString &location)
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "proxyForService for location: " << location;
+#endif
+ // Create client-side session for the IPC and connect it to the service
+ // provide. If service provider is not up, it will be started.
+ // Connecting is tried few times in a loop, because if service starting is
+ // done at device startup, everything may not be ready yet.
+ RServiceSession *session = new RServiceSession(location);
+ int err = session->Connect();
+ int i = 0;
+ while (err != KErrNone) {
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "proxyForService Connecting in loop: " << i;
+#endif
+ if (i > 10) {
+ qWarning() << "QtSFW failed to connect to service provider.";
+ return NULL;
+ }
+ User::After(50);
+ err = session->Connect();
+ i++;
+ }
+
+ // Create IPC endpoint. In practice binds the communication session and abstracting
+ // class presenting the IPC endoint.
+ SymbianClientEndPoint* ipcEndPoint = new SymbianClientEndPoint(session);
+ ipcEndPoint->setParent(session);
+ // Create an active message solicitor, which listens messages from server
+ ServiceMessageListener* messageListener = new ServiceMessageListener(session, ipcEndPoint);
+ // Create object endpoint, which handles the metaobject protocol.
+ ObjectEndPoint* endPoint = new ObjectEndPoint(ObjectEndPoint::Client, ipcEndPoint);
+ endPoint->setParent(session);
+ QObject *proxy = endPoint->constructProxy(entry);
+ session->setParent(proxy);
+ QObject::connect(session, SIGNAL(errorUnrecoverableIPCFault(QService::UnrecoverableIPCError)),
+ proxy, SIGNAL(errorUnrecoverableIPCFault(QService::UnrecoverableIPCError)));
+ return proxy;
+}
+
+RServiceSession::RServiceSession(QString address)
+: iSize(0), iListener(0), iDataSizes(KIpcBufferMinimumSize),iServerStarted(EFalse)
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "RServiceSession() for address: " << address;
+#endif
+ qt_symbian_throwIfError(iMessageFromServer.Create(KIpcBufferMinimumSize));
+ iServerAddress = address;
+}
+
+RServiceSession::~RServiceSession()
+{
+ delete iListener;
+ Close();
+ iMessageFromServer.Close();
+}
+
+void RServiceSession::setListener(ServiceMessageListener *listener)
+{
+ iListener = listener;
+}
+
+void RServiceSession::Close()
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "RServiceSession close()";
+#endif
+ RSessionBase::Close();
+}
+
+TInt RServiceSession::Connect()
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "RServiceSession Connect()";
+#endif
+ TInt err=KErrUnknown;
+ if(!iServerStarted){
+ TInt err = StartServer();
+ if (err == KErrNone) {
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "StartServer successful, Creating session.";
+#endif
+ iServerStarted = ETrue;
+ }
+ }
+ TPtrC serviceAddressPtr(reinterpret_cast<const TUint16*>(iServerAddress.utf16()));
+ err = CreateSession(serviceAddressPtr, Version());
+
+ return err;
+}
+
+TVersion RServiceSession::Version() const
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "RServiceSession Version()";
+#endif
+ return TVersion(KServerMajorVersionNumber, KServerMinorVersionNumber, KServerBuildVersionNumber);
+}
+
+void RServiceSession::SendServicePackage(const QServicePackage& aPackage)
+{
+ // Serialize the package into byte array, wrap it in descriptor,
+ // and send to service provider.
+ QByteArray block;
+ QDataStream out(&block, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_6);
+ out << aPackage;
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "SendServicePackage: Size of package sent from client to server: " << block.count();
+#endif
+ TPtrC8 ptr8((TUint8*)(block.constData()), block.size());
+ TIpcArgs args(&ptr8, &iError);
+ TInt err = SendReceive(EServicePackage, args);
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "SendServicePackage error code received: " << err;
+#endif
+ if(err != KErrNone){
+ enum QService::UnrecoverableIPCError e = QService::ErrorUnknown;
+ switch(err){
+ case KErrServerTerminated:
+ e = QService::ErrorServiceNoLongerAvailable;
+ break;
+ case KErrNoMemory:
+ case KErrServerBusy: // if the slots are full, something is really wrong
+ e = QService::ErrorOutofMemory;
+ break;
+ }
+ emit errorUnrecoverableIPCFault(e);
+ }
+}
+
+void RServiceSession::addDataSize(TInt dataSize)
+{
+ iDataSizes.addSample(dataSize);
+}
+
+// StartServer() checks if the service is already published by someone (i.e. can be found
+// from Kernel side). If not, it will start the process that provides the service.
+TInt RServiceSession::StartServer()
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "RServiceSession::StartServer()";
+#endif
+ TInt ret = KErrNone;
+ TPtrC serviceAddressPtr(reinterpret_cast<const TUint16*>(iServerAddress.utf16()));
+ TFindServer findServer(serviceAddressPtr);
+ TFullName name;
+ // Looks up from Kernel-side if there are active servers with the given name.
+ // If not found, a process providing the service needs to be started.
+ if (findServer.Next(name) != KErrNone) {
+#if defined(__WINS__) && !defined(SYMBIAN_EMULATOR_SUPPORTS_PERPROCESS_WSD)
+ qWarning("WINS Support for QSFW OOP not implemented.");
+#else
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "RServiceSession::StartServer() Service not found. Starting " << iServerAddress;
+#endif
+ TRequestStatus status;
+ RProcess serviceServerProcess;
+ ret = serviceServerProcess.Create(serviceAddressPtr, KNullDesC);
+ if (ret != KErrNone) {
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "StartServer RProcess::Create failed: " << ret;
+#endif
+ return ret;
+ }
+ // Point of synchronization. Waits until the started process calls
+ // counterpart of this function (quits wait also if process dies / panics).
+ serviceServerProcess.Rendezvous(status);
+
+ if (status != KRequestPending) {
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "StartServer Service Server Process Rendezvous() failed, killing process.";
+#endif
+ serviceServerProcess.Kill(KErrNone);
+ serviceServerProcess.Close();
+ return KErrGeneral;
+ } else {
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "StartServer Service Server Process Rendezvous() successful, resuming process.";
+#endif
+ serviceServerProcess.Resume();
+ }
+ User::WaitForRequest(status);
+ if (status != KErrNone){
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("RTR Process Resume failed.");
+#endif
+ serviceServerProcess.Close();
+ return status.Int();
+ }
+ // Free the handle to the process (RHandleBase function, does not 'close process')
+ serviceServerProcess.Close();
+#endif // __WINS__
+ } else {
+ qDebug() << "RServiceSession::StartServer() GTR Service found from Kernel, no need to start process.";
+ }
+ return ret;
+}
+
+/* Since the average size will not change in the middle of a fragmented message
+ * trasnfer actual updates to buffer size will happen only when a new message
+ * arrives */
+void RServiceSession::updateIpcBufferSize()
+{
+ TInt weightedAvg = iDataSizes.averageWeighted();
+
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "updateIpcBufferSize(): current weighted average of data size is: "<<weightedAvg;
+ qDebug() << "Current IPC Buffer size is: "<<iMessageFromServer.MaxLength();
+#endif
+ TInt newSize = iMessageFromServer.MaxLength();
+ if(weightedAvg > iMessageFromServer.MaxLength()){
+ newSize = iMessageFromServer.MaxLength()*2;
+ }
+ else if(weightedAvg < iMessageFromServer.MaxLength()/2){
+
+ newSize = iMessageFromServer.MaxLength()/2;
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "updateIpcBufferSize(): current weighted average of data size is:(2) "<<weightedAvg<<" max/2";
+#endif
+ }
+
+ if(newSize < KIpcBufferMinimumSize)
+ newSize = KIpcBufferMinimumSize;
+ else if(newSize > KIpcBufferMaximumSize)
+ newSize = KIpcBufferMaximumSize;
+
+
+ if(newSize != iMessageFromServer.MaxLength()) {
+
+ iMessageFromServer.SetLength(0);
+ //If realloc fails the old descriptor is left unchanged.
+ iMessageFromServer.ReAlloc(newSize);
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "updateIpcBufferSize(): New Size of IPC Buffer: "<<newSize;
+#endif
+ }
+}
+
+void RServiceSession::ListenForPackages(TRequestStatus& aStatus)
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "GTR RServiceSession::ListenForPackages(), iSize: " << iSize();
+#endif
+ updateIpcBufferSize();
+ iArgs.Set(0, &iMessageFromServer);
+ // Total Size of returned messaage,which might differ from the amount of data in iMessageFromServer
+ iArgs.Set(1, &iSize);
+ iArgs.Set(2, &iError);
+
+ SendReceive(EPackageRequest, iArgs, aStatus);
+}
+
+void RServiceSession::CancelListenForPackages()
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("RServiceSession::CancelListenForPackages -- 2");
+#endif
+ TInt err = SendReceive(EPackageRequestCancel, TIpcArgs(NULL));
+ if(err != KErrNone){
+ enum QService::UnrecoverableIPCError e = QService::ErrorUnknown;
+ switch(err){
+ case KErrServerTerminated:
+ e = QService::ErrorServiceNoLongerAvailable;
+ break;
+ case KErrNoMemory:
+ case KErrServerBusy: // if the slots are full, something is really wrong
+ e = QService::ErrorOutofMemory;
+ break;
+ }
+ emit errorUnrecoverableIPCFault(e);
+ }
+}
+
+void RServiceSession::ipcFailure(QService::UnrecoverableIPCError err)
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("RServiceSession::ipcFailure ipc Fault reported");
+#endif
+ emit errorUnrecoverableIPCFault(err);
+}
+
+static const TUint myRangeCount = 1;
+static const TInt myRanges[myRangeCount] =
+ {
+ 0 //range is 0-Max inclusive
+ };
+static const TUint8 myElementsIndex[myRangeCount] =
+ {
+ CPolicyServer::EAlwaysPass
+ };
+static const CPolicyServer::TPolicyElement myElements[] =
+ {
+ {_INIT_SECURITY_POLICY_PASS } // Dummy entry
+ };
+static const CPolicyServer::TPolicy myPolicy =
+ {
+ CPolicyServer::ECustomCheck, //specifies all connect attempts should pass
+ myRangeCount,
+ myRanges,
+ myElementsIndex,
+ myElements,
+ };
+
+CServiceProviderServer::CServiceProviderServer(QRemoteServiceRegisterSymbianPrivate* aOwner)
+ : CPolicyServer(EPriorityNormal, myPolicy), iSessionCount(0), iOwner(aOwner), iFilter(0)
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("CServiceProviderServer constructor");
+#endif
+ Q_ASSERT(aOwner);
+}
+
+CPolicyServer::TCustomResult CServiceProviderServer::CustomSecurityCheckL(const RMessage2 &aMessage, TInt &aAction, TSecurityInfo &aMissing)
+{
+ if(iFilter){
+ if(iFilter(reinterpret_cast<const void *>(&aMessage))){
+ return CPolicyServer::EPass;
+ }
+ else {
+ return CPolicyServer::EFail;
+ }
+ }
+ return CPolicyServer::EPass;
+}
+
+CSession2* CServiceProviderServer::NewSessionL(const TVersion &aVersion, const RMessage2 &aMessage) const
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("CServiceProviderServer::NewSessionL()");
+#endif
+ if (!User::QueryVersionSupported(TVersion(KServerMajorVersionNumber,
+ KServerMinorVersionNumber, KServerBuildVersionNumber), aVersion))
+ {
+ User::Leave(KErrNotSupported);
+ }
+ CServiceProviderServerSession* session = CServiceProviderServerSession::NewL(*const_cast<CServiceProviderServer*>(this));
+ iOwner->processIncoming(session);
+ return session;
+}
+
+void CServiceProviderServer::IncreaseSessions()
+{
+ iSessionCount++;
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << ">>>> CServiceProviderServer incremented session count to: " << iSessionCount;
+#endif
+}
+
+void CServiceProviderServer::DecreaseSessions()
+{
+ iSessionCount--;
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "<<<< CServiceProviderServer decremented session count to: " << iSessionCount;
+#endif
+ if(iSessionCount == 0){
+ Cancel();
+ if(iOwner->quitOnLastInstanceClosed())
+ QCoreApplication::exit();
+ }
+}
+
+void CServiceProviderServer::setSecurityFilter(QRemoteServiceRegister::SecurityFilter filter)
+{
+ iFilter = filter;
+}
+
+CServiceProviderServerSession *CServiceProviderServerSession::NewL(CServiceProviderServer &aServer)
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("CServiceProviderServerSession::NewL()");
+#endif
+ CServiceProviderServerSession *self = CServiceProviderServerSession::NewLC(aServer);
+ CleanupStack::Pop(self);
+ return self;
+}
+
+CServiceProviderServerSession *CServiceProviderServerSession::NewLC(CServiceProviderServer &aServer)
+{
+ CServiceProviderServerSession* self = new (ELeave) CServiceProviderServerSession(aServer);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+}
+
+CServiceProviderServerSession::CServiceProviderServerSession(CServiceProviderServer &aServer)
+ : iServer(aServer)
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("CServiceProviderServerSession constructor");
+#endif
+ iServer.IncreaseSessions();
+}
+
+void CServiceProviderServerSession::ConstructL()
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("OTR CServiceProviderServerSession::ConstructL()");
+#endif
+ iTotalSize = 0; // No data
+ iBlockData.clear();// clear the buffer
+}
+
+CServiceProviderServerSession::~CServiceProviderServerSession()
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("CServiceProviderServerSession destructor");
+#endif
+ iServer.DecreaseSessions();
+ delete iByteArray;
+ delete iOwner;
+}
+
+void CServiceProviderServerSession::ServiceL(const RMessage2 &aMessage)
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "CServiceProviderServerSession::ServiceL for message: " << aMessage.Function();
+#endif
+ switch (aMessage.Function())
+ {
+ case EServicePackage:
+ HandleServicePackageL(aMessage);
+ aMessage.Complete(KErrNone);
+ break;
+ case EPackageRequest:
+ HandlePackageRequestL(aMessage);
+ break;
+ case EPackageRequestCancel:
+ HandlePackageRequestCancelL(aMessage);
+ break;
+ }
+}
+
+void CServiceProviderServerSession::HandleServicePackageL(const RMessage2& aMessage)
+{
+ // Reproduce the serialized data.
+ HBufC8* servicePackageBuf8 = HBufC8::New(aMessage.GetDesLength(0));
+ if (!servicePackageBuf8) {
+ User::Leave( KErrNoMemory );
+ }
+
+ TPtr8 ptrToBuf(servicePackageBuf8->Des());
+ TInt ret = KErrNone;
+ TRAP(ret, aMessage.ReadL(0, ptrToBuf));
+ if (ret != KErrNone) {
+ // TODO: is this error handleing correct
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "HandleServicePackageL. Message read failed: " << ret;
+#endif
+ //iDb->lastError().setError(DBError::UnknownError);
+ //aMessage.Write(1, LastErrorCode());
+ delete servicePackageBuf8;
+ User::Leave( ret );
+ }
+
+ QByteArray byteArray((const char*)ptrToBuf.Ptr(), ptrToBuf.Length());
+ QDataStream in(byteArray);
+ QServicePackage results;
+ in >> results;
+
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "CServiceProviderServerSession Reproduced service package: ";
+ printServicePackage(results);
+#endif
+ iOwner->packageReceived(results);
+ delete servicePackageBuf8;
+}
+
+void CServiceProviderServerSession::SetParent(SymbianServerEndPoint *aOwner)
+{
+ iOwner = aOwner;
+}
+
+void CServiceProviderServerSession::HandlePackageRequestL(const RMessage2& aMessage)
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("HandlePackageRequestL(). Setting pending true and storing message.");
+#endif
+ iMsg = aMessage;
+ iPendingPackageRequest = ETrue;
+ if(!iPendingPackageQueue.isEmpty())
+ SendServicePackageL(iPendingPackageQueue.dequeue());
+}
+
+void CServiceProviderServerSession::HandlePackageRequestCancelL(const RMessage2& aMessage)
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("HandlePackageRequestCancelL");
+#endif
+ if (iPendingPackageRequest) {
+ iMsg.Complete(KErrCancel);
+ iPendingPackageRequest = EFalse;
+ }
+ aMessage.Complete(EPackageRequestComplete);
+}
+
+void CServiceProviderServerSession::SendServicePackageL(const QServicePackage& aPackage)
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("CServiceProviderServerSession:: SendServicePackage for package: ");
+ printServicePackage(aPackage);
+#endif
+ if (iPendingPackageRequest) {
+ if(iBlockData.isEmpty()){
+ // Serialize the package
+ QDataStream out(&iBlockData, QIODevice::WriteOnly);
+ out.setVersion(QDataStream::Qt_4_6);
+ out << aPackage;
+ iTotalSize = iBlockData.size();
+ }
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "Size of package sent from server to client: " << iBlockData.count();
+ qDebug() << "Size of buffer from client: " << iMsg.GetDesMaxLength(0);
+#endif
+
+ int size = iBlockData.size();
+ if(size > iMsg.GetDesMaxLength(0)){
+ size = iMsg.GetDesMaxLength(0);
+ // enequeue the package so we send the next chunk
+ // when the next request comes through
+ iPendingPackageQueue.prepend(aPackage);
+ }
+ TPtrC8 ptr8((TUint8*)(iBlockData.constData()), size);
+ iMsg.WriteL(0, ptr8);
+ iBlockData.remove(0, size);
+//#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+// if(status == KErrOverflow){
+// qDebug() << "OTR Server to client, got overflow, sending 0 bytes";
+// }
+// else if(status != KErrNone){
+// qDebug() << "OTR SendServicePackage: error code from send: " << status;
+// }
+//#endif
+ TPckgBuf<TInt> totalSize(iTotalSize);
+ iMsg.WriteL(1,totalSize);
+ iMsg.Complete(EPackageRequestComplete);
+ iPendingPackageRequest = EFalse;
+ } else {
+ iPendingPackageQueue.enqueue(aPackage);
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qWarning() << "RTR SendServicePackage: service package from server to client queued - no pending receive request.";
+#endif
+ }
+}
+
+ServiceMessageListener::ServiceMessageListener(RServiceSession* aSession, SymbianClientEndPoint* aOwner)
+ : CActive(EPriorityNormal),
+ iClientSession(aSession),
+ iOwnerEndPoint(aOwner)
+{
+ Q_ASSERT(iClientSession);
+ Q_ASSERT(iOwnerEndPoint);
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("ServiceMessageListener constructor");
+#endif
+ aSession->setListener(this);
+ CActiveScheduler::Add(this);
+ StartListening();
+}
+
+ServiceMessageListener::~ServiceMessageListener()
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("ServiceMessageListener destructor");
+#endif
+ Cancel();
+}
+
+void ServiceMessageListener::StartListening()
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("ServiceMessageListener::StartListening");
+#endif
+ iClientSession->ListenForPackages(iStatus);
+ SetActive();
+}
+
+void ServiceMessageListener::DoCancel()
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug("ServiceMessageListener::DoCancel");
+#endif
+ iClientSession->CancelListenForPackages();
+}
+
+void ServiceMessageListener::RunL()
+{
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "ServiceMessageListener::RunL for iStatus.Int(should be 4): " << iStatus.Int();
+#endif
+ if (iStatus.Int() == EPackageRequestComplete) {
+ // Client side has received a service package from server. Pass it onwards and
+ // issue new pending request.
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "RunL length of the package received client side is: " << iClientSession->iMessageFromServer.Length();
+#endif
+ if(iClientSession->iMessageFromServer.Length() == 0){
+ // we received 0 bytes from the other side,
+ // normally because it tried to write more bytes
+ // than were in the TDes
+ User::Leave(KErrTooBig);
+ }
+
+ if(!iByteArray.length()){
+ /* Helps client session to calculate an optimum IPC buffer size */
+ iClientSession->addDataSize(iClientSession->iSize());
+ }
+
+ iByteArray.append((const char*)iClientSession->iMessageFromServer.Ptr(),
+ iClientSession->iMessageFromServer.Length());
+ if(iByteArray.length() >= iClientSession->iSize()){
+ QDataStream in(iByteArray);
+ iByteArray.clear();
+ QServicePackage results;
+ in >> results;
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+ qDebug() << "ServiceMessageListener Reproduced service package: ";
+ printServicePackage(results);
+#endif
+ iOwnerEndPoint->PackageReceived(results);
+ }
+ StartListening();
+ }
+ else if(iStatus.Int() < 0){
+ TInt s = iStatus.Int();
+ switch(s){
+ case KErrServerTerminated:
+ iClientSession->ipcFailure(QService::ErrorServiceNoLongerAvailable);
+ break;
+ case KErrServerBusy:
+ case KErrNoMemory:
+ iClientSession->ipcFailure(QService::ErrorOutofMemory);
+ break;
+ }
+ }
+}
+
+#include "moc_qremoteserviceregister_s60_p.cpp"
+#include "qremoteserviceregister_s60.moc"
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/qremoteserviceregister_s60_p.h b/src/serviceframework/ipc/qremoteserviceregister_s60_p.h
new file mode 100644
index 00000000..48799546
--- /dev/null
+++ b/src/serviceframework/ipc/qremoteserviceregister_s60_p.h
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTESERVICEREGISTER_S60_P_H
+#define QREMOTESERVICEREGISTER_S60_P_H
+
+//#define QT_SFW_SYMBIAN_IPC_DEBUG
+
+#include "qremoteserviceregister.h"
+#include "qremoteserviceregister_p.h"
+//#include "qremoteserviceclassregister.h"
+#include "qservicepackage_p.h"
+#include "qservice.h"
+#include <e32base.h>
+
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+#include <QDebug>
+#endif
+
+#include <QQueue>
+
+QTM_BEGIN_NAMESPACE
+
+class ServiceMessageListener;
+
+const TUint KServerMajorVersionNumber = 1;
+const TUint KServerMinorVersionNumber = 0;
+const TUint KServerBuildVersionNumber = 0;
+
+enum TServiceProviderRequest
+{
+ EServicePackage = 1,
+ EPackageRequest = 2,
+ EPackageRequestCancel = 3,
+ EPackageRequestComplete = 4
+};
+
+const TInt KIpcBufferMinimumSize = 256; //Bytes
+const TInt KIpcBufferMaximumSize = 1024*16;
+
+// Forward declarations
+class ObjectEndPoint;
+class CServiceProviderServerSession;
+class CServiceProviderServer;
+class SymbianServerEndPoint;
+class SymbianClientEndPoint;
+class QRemoteServiceRegisterSymbianPrivate;
+
+// Type definitions
+typedef TPckgBuf<TInt> TError;
+
+#ifdef QT_SFW_SYMBIAN_IPC_DEBUG
+void printServicePackage(const QServicePackage& package);
+#endif
+
+//Internal class which calculates the Simple and Weighted moving average of
+//data sizes from the Service. The average calculated can be used to decide a
+//optimal IPC buffer size.
+template <int WINDOW>
+class MovingAverage
+{
+public:
+ MovingAverage(TInt median):m_index(0),m_averageSimple((TReal)median),m_averageWeighted((TReal)median)
+ {
+ m_weightedSum = m_sum =0;
+ for (TInt i=0;i<WINDOW;i++){
+ m_samples[i]=median;
+ m_weightedSum += m_samples[i]*(i+1);
+ m_sum += m_samples[i];
+ }
+ }
+ int average(){return static_cast<TInt>(m_averageSimple);}
+ int averageWeighted(){return static_cast<TInt>(m_averageWeighted);}
+ void addSample(int sample)
+ {
+ int pop = m_samples[m_index];
+ m_samples[m_index] = sample;
+ m_weightedSum = m_weightedSum + WINDOW*sample - m_sum;
+ m_sum = m_sum + sample - pop;
+ m_averageSimple = m_averageSimple + ((TReal)sample -pop)/WINDOW;
+ m_averageWeighted = (TReal)m_weightedSum*2/(WINDOW*(WINDOW+1));
+ m_index = (m_index+1)%WINDOW;
+ }
+private:
+ int m_samples[WINDOW];
+ TInt m_index;
+ TInt m_weightedSum;
+ /* The sum of all the samples */
+ TInt m_sum;
+ TReal m_averageSimple;
+ TReal m_averageWeighted;
+};
+
+
+// Internal class handling the actual communication with the service provider.
+// Communication is based on standard Symbian client-server architecture.
+class RServiceSession : public QObject, public RSessionBase
+{
+ Q_OBJECT
+public:
+ RServiceSession(QString address);
+ virtual ~RServiceSession();
+ TInt Connect();
+ void Close();
+ TVersion Version() const;
+ void SendServicePackage(const QServicePackage& aPackage);
+ /* Adds sample to calculate the average */
+ void addDataSize(TInt dataSize);
+
+ public:
+ RBuf8 iMessageFromServer;
+ TPckgBuf<TInt> iSize; // TPckgBuf type can be used directly as IPC parameter
+
+ void setListener(ServiceMessageListener* listener);
+
+public slots:
+ void ipcFailure(QService::UnrecoverableIPCError);
+
+signals:
+ void Disconnected();
+ void errorUnrecoverableIPCFault(QService::UnrecoverableIPCError);
+
+protected:
+ void ListenForPackages(TRequestStatus& aStatus);
+ void CancelListenForPackages();
+
+private:
+ TInt StartServer();
+ /* Re-Sizes IPC buffer if needed */
+ void updateIpcBufferSize();
+
+private:
+ TIpcArgs iArgs; // These two are used in actively listening to server
+ TError iError;
+ QString iServerAddress;
+ ServiceMessageListener* iListener;
+ MovingAverage<10> iDataSizes;
+ TBool iServerStarted;
+ friend class ServiceMessageListener;
+};
+
+// needed for creating server thread.
+const TUint KDefaultHeapSize = 0x10000;
+
+class CServiceProviderServer : public CPolicyServer
+ {
+ public:
+ CServiceProviderServer(QRemoteServiceRegisterSymbianPrivate* aOwner);
+ CSession2* NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const;
+
+ public:
+
+ void IncreaseSessions();
+ void DecreaseSessions();
+
+ void setSecurityFilter(QRemoteServiceRegister::SecurityFilter filter);
+
+ protected:
+ virtual TCustomResult CustomSecurityCheckL(const RMessage2 &,TInt &,TSecurityInfo &);
+
+ private:
+
+ int iSessionCount;
+ QRemoteServiceRegisterSymbianPrivate* iOwner;
+ QRemoteServiceRegister::SecurityFilter iFilter;
+ };
+
+class CServiceProviderServerSession : public CSession2
+ {
+ public:
+ static CServiceProviderServerSession* NewL(CServiceProviderServer& aServer);
+ static CServiceProviderServerSession* NewLC(CServiceProviderServer& aServer);
+ virtual ~CServiceProviderServerSession();
+ void ServiceL(const RMessage2& aMessage);
+ void SetParent(SymbianServerEndPoint* aOwner);
+ void SendServicePackageL(const QServicePackage& aPackage);
+
+ void HandleServicePackageL(const RMessage2& aMessage);
+ void HandlePackageRequestL(const RMessage2& aMessage);
+ void HandlePackageRequestCancelL(const RMessage2& aMessage);
+
+ private:
+ CServiceProviderServerSession(CServiceProviderServer& aServer);
+ void ConstructL();
+
+ private:
+ CServiceProviderServer& iServer;
+ SymbianServerEndPoint* iOwner;
+ QByteArray* iByteArray;
+ RMessage2 iMsg; // For replying pending service package requests
+ QQueue<QServicePackage> iPendingPackageQueue;
+ TBool iPendingPackageRequest;
+ QByteArray iBlockData;
+ int iTotalSize;
+ };
+
+
+class QRemoteServiceRegisterSymbianPrivate: public QRemoteServiceRegisterPrivate
+{
+ Q_OBJECT
+
+public:
+ QRemoteServiceRegisterSymbianPrivate(QObject* parent);
+ ~QRemoteServiceRegisterSymbianPrivate();
+ void publishServices(const QString& ident );
+ static QObject* proxyForService(const QRemoteServiceRegister::Entry& entry, const QString& location);
+ void processIncoming(CServiceProviderServerSession* session);
+
+ virtual QRemoteServiceRegister::SecurityFilter setSecurityFilter(QRemoteServiceRegister::SecurityFilter filter);
+
+private:
+ CServiceProviderServer *m_server;
+};
+
+// A helper class that actively listens for serviceprovider messages.
+// Needed because Symbian server cannot send messages without active request
+// from the client.
+class ServiceMessageListener : public CActive
+{
+public:
+ ServiceMessageListener(RServiceSession* aSession, SymbianClientEndPoint* aOwner);
+ ~ServiceMessageListener();
+
+protected:
+ void StartListening();
+ // from CActive baseclass
+ void DoCancel();
+ void RunL();
+
+private:
+ RServiceSession* iClientSession;
+ SymbianClientEndPoint* iOwnerEndPoint;
+ QByteArray iByteArray;
+};
+
+QTM_END_NAMESPACE
+
+#endif // QREMOTESERVICEREGISTER_S60_P_H
diff --git a/src/serviceframework/ipc/qremoteserviceregisterentry_p.h b/src/serviceframework/ipc/qremoteserviceregisterentry_p.h
new file mode 100644
index 00000000..8aa0cfa9
--- /dev/null
+++ b/src/serviceframework/ipc/qremoteserviceregisterentry_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTESERVICEREGISTERENTRY_P_H
+#define QREMOTESERVICEREGISTERENTRY_P_H
+
+#include <QExplicitlySharedDataPointer>
+#include <QString>
+
+#include "qremoteserviceregister.h"
+
+QTM_BEGIN_NAMESPACE
+
+class QRemoteServiceRegisterEntryPrivate : public QSharedData
+{
+public:
+ QRemoteServiceRegisterEntryPrivate()
+ : meta(0), cptr(0), instanceType(QRemoteServiceRegister::PrivateInstance)
+ {
+ }
+
+ QRemoteServiceRegisterEntryPrivate(QRemoteServiceRegisterEntryPrivate &other)
+ : QSharedData(other), iface(other.iface),
+ service(other.service), ifaceVersion(other.ifaceVersion),
+ meta(other.meta), cptr(other.cptr), instanceType(other.instanceType)
+ {
+ }
+
+ QString iface;
+ QString service;
+ QString ifaceVersion;
+ const QMetaObject* meta;
+ QRemoteServiceRegister::CreateServiceFunc cptr;
+ QRemoteServiceRegister::InstanceType instanceType;
+};
+
+QTM_END_NAMESPACE
+
+#endif
diff --git a/src/serviceframework/ipc/qservicemetaobject_dbus.cpp b/src/serviceframework/ipc/qservicemetaobject_dbus.cpp
new file mode 100644
index 00000000..6dbb79c1
--- /dev/null
+++ b/src/serviceframework/ipc/qservicemetaobject_dbus.cpp
@@ -0,0 +1,580 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qservicemetaobject_dbus_p.h"
+#include "qmetaobjectbuilder_p.h"
+#include "qsignalintercepter_p.h"
+#include <QDebug>
+
+QTM_BEGIN_NAMESPACE
+
+class ServiceMetaSignalIntercepter : public QSignalIntercepter
+{
+
+public:
+ ServiceMetaSignalIntercepter(QObject* sender, const QByteArray& signal, QServiceMetaObjectDBus* parent)
+ : QSignalIntercepter(sender, signal, parent), serviceDBus(parent)
+ {
+
+ }
+
+ void setMetaIndex(int index)
+ {
+ metaIndex = index;
+ }
+
+protected:
+ void activated( const QList<QVariant>& args )
+ {
+ serviceDBus->activateMetaSignal(metaIndex, args);
+ }
+private:
+ QServiceMetaObjectDBus* serviceDBus;
+ int metaIndex;
+};
+
+
+class QServiceMetaObjectDBusPrivate
+{
+public:
+ QObject *service;
+ const QMetaObject *serviceMeta;
+ const QMetaObject *dbusMeta;
+};
+
+QServiceMetaObjectDBus::QServiceMetaObjectDBus(QObject* service, bool signalsObject)
+ : QDBusAbstractAdaptor(service)
+{
+ // Register our DBus custom type object
+ qRegisterMetaType<QTM_PREPEND_NAMESPACE(QServiceUserTypeDBus)>();
+ qDBusRegisterMetaType<QTM_PREPEND_NAMESPACE(QServiceUserTypeDBus)>();
+
+ // Generate our DBus meta object
+ d = new QServiceMetaObjectDBusPrivate();
+ d->service = service;
+ d->serviceMeta = service->metaObject();
+ d->dbusMeta = dbusMetaObject(signalsObject);
+
+ // Relay signals from the service to the constructed DBus meta object
+ connectMetaSignals(signalsObject);
+}
+
+QServiceMetaObjectDBus::~QServiceMetaObjectDBus()
+{
+ if (d->dbusMeta)
+ qFree(const_cast<QMetaObject*>(d->dbusMeta));
+
+ delete d;
+}
+
+/*!
+ Relays all signals from the service object to the converted DBus service adaptor so
+ that when a service signal is emitted the DBus object will emit the counterpart signal
+*/
+void QServiceMetaObjectDBus::connectMetaSignals(bool signalsObject) {
+ if (!signalsObject) {
+ // Automatically relay signals from service object to adaptor
+ setAutoRelaySignals(true);
+
+ // Connect signals with custom arguments
+ int methodCount = d->serviceMeta->methodCount();
+ for (int i = 0; i < methodCount; i++) {
+ QMetaMethod mm = d->serviceMeta->method(i);
+
+
+ if (mm.methodType() == QMetaMethod::Signal) {
+ QByteArray sig(mm.signature());
+ bool customType = false;
+ const QList<QByteArray> pTypes = mm.parameterTypes();
+ const int pTypesCount = pTypes.count();
+
+ // Ignore all QObject calls
+ const QMetaObject *mo = QObject::metaObject();
+ int qobjectIndex = mo->indexOfMethod(sig);
+ if (qobjectIndex >= 0)
+ continue;
+
+ // Detects custom types as passed arguments
+ for (int arg = 0; arg < pTypesCount; arg++) {
+ const QByteArray& type = pTypes[arg];
+ int variantType = QVariant::nameToType(type);
+ if (variantType == QVariant::UserType) {
+ sig.replace(QByteArray(type), QByteArray("QDBusVariant"));
+ customType = true;
+ }
+ }
+
+ // Connects the service signal to the corresponding DBus service signal
+ if (customType) {
+ QByteArray signal = mm.signature();
+ ServiceMetaSignalIntercepter *intercept =
+ new ServiceMetaSignalIntercepter(d->service, "2"+signal, this);
+ intercept->setMetaIndex(i);
+ }
+ }
+ }
+ }
+}
+
+/*!
+ Relays the activation to the DBus object signal with the given id and arguments list when the
+ intercepter for signals with custom arguments has been activated. This bypasses the metacall
+ which usually does the relaying for signals with standard arguments since no pre-connection
+ conversions are required.
+*/
+void QServiceMetaObjectDBus::activateMetaSignal(int id, const QVariantList& args)
+{
+ QMetaMethod method = d->serviceMeta->method(id);
+
+ // Converts the argument list to values supported by the QtDBus type system
+ QVariantList convertedList = args;
+ QByteArray sig(method.signature());
+ QList<QByteArray> params = method.parameterTypes();
+
+ for (int i = 0; i < params.size(); i++) {
+ QVariant dbusVariant = args[i];
+
+ // Convert custom types
+ const QByteArray& type = params[i];
+ int variantType = QVariant::nameToType(type);
+ if (variantType == QVariant::UserType) {
+ variantType = QMetaType::type(type);
+
+ if (variantType >= QMetaType::User) {
+ // Wrap custom types in a QDBusVariant of the type name and
+ // a buffer of its variant-wrapped data
+ QByteArray buffer;
+ QDataStream stream(&buffer, QIODevice::ReadWrite | QIODevice::Append);
+ stream << args[i];
+
+ QServiceUserTypeDBus customType;
+ customType.typeName = type;
+ customType.variantBuffer = buffer;
+
+ QDBusVariant replacement(QVariant::fromValue(customType));
+ convertedList.replace(i, QVariant::fromValue(replacement));
+ }
+
+ sig.replace(QByteArray(type), QByteArray("QDBusVariant"));
+ }
+ }
+
+ // Activate the DBus object signal call
+ const int numArgs = convertedList.size();
+ QVarLengthArray<void *, 32> a( numArgs+1 );
+ a[0] = 0;
+
+ const QList<QByteArray> pTypes = method.parameterTypes();
+ for ( int arg = 0; arg < numArgs; ++arg ) {
+ if (pTypes.at(arg) == "QVariant")
+ a[arg+1] = (void *)&( convertedList[arg] );
+ else
+ a[arg+1] = (void *)( convertedList[arg].data() );
+ }
+
+ int dbusIndex = d->dbusMeta->indexOfSignal(sig);
+ QMetaObject::activate(this, dbusIndex, a.data());
+}
+
+
+/*!
+ Build a metaobject that represents the service object as a valid service that
+ satisfies the QtDBus type system.
+*/
+const QMetaObject* QServiceMetaObjectDBus::dbusMetaObject(bool signalsObject) const
+{
+ // Create a meta-object to represent all the contents of our service on DBus
+ QMetaObjectBuilder builder;
+
+ builder.setClassName(d->serviceMeta->className());
+ builder.setSuperClass(d->serviceMeta->superClass()); // needed?
+
+ const QMetaObject* mo = d->serviceMeta;
+ while (mo && strcmp(mo->className(), "QObject")) {
+ // Add our methods, signals and slots
+ for (int i = mo->methodOffset(); i < mo->methodCount(); i++) {
+ QMetaMethod mm = mo->method(i);
+
+ if (signalsObject && mm.methodType() != QMetaMethod::Signal)
+ continue;
+
+ // Convert QVariant and custom return types to QDBusVariants
+ QByteArray ret(mm.typeName());
+ const QByteArray& type = mm.typeName();
+ int variantType = QVariant::nameToType(type);
+ if (variantType == QVariant::UserType) {
+ ret = QByteArray("QDBusVariant");
+ }
+
+ // Convert QVariant and custom argument types to QDBusVariants
+ QByteArray sig(mm.signature());
+ const QList<QByteArray> pTypes = mm.parameterTypes();
+ const int pTypesCount = pTypes.count();
+ for (int i=0; i < pTypesCount; i++) {
+ const QByteArray& type = pTypes[i];
+ int variantType = QVariant::nameToType(type);
+ if (variantType == QVariant::UserType) {
+ sig.replace(QByteArray(type), QByteArray("QDBusVariant"));
+ }
+ }
+
+ // Add a MetaMethod with converted signature to our builder
+ QMetaMethodBuilder method;
+ switch (mm.methodType()) {
+ case QMetaMethod::Method:
+ method = builder.addMethod(sig);
+ break;
+ case QMetaMethod::Slot:
+ method = builder.addSlot(sig);
+ break;
+ case QMetaMethod::Signal:
+ method = builder.addSignal(sig);
+ break;
+ default:
+ break;
+ }
+
+ // Make sure our built MetaMethod is identical, excluding conversion
+ method.setReturnType(ret);
+ method.setParameterNames(mm.parameterNames());
+ method.setTag(mm.tag());
+ method.setAccess(mm.access());
+ method.setAttributes(mm.attributes());
+ }
+
+ if (signalsObject)
+ return builder.toMetaObject();
+
+ // Add our property accessor methods
+ // NOTE: required because read/reset properties over DBus require adaptors
+ // otherwise a metacall won't be invoked as QMetaObject::ReadProperty
+ // or QMetaObject::ResetProperty
+ QMetaMethodBuilder readProp;
+ readProp = builder.addMethod(QByteArray("propertyRead(QString)"));
+ readProp.setReturnType(QByteArray("QDBusVariant"));
+ QList<QByteArray> params;
+ params << QByteArray("name");
+ readProp.setParameterNames(params);
+
+ QMetaMethodBuilder resetProp;
+ resetProp = builder.addMethod(QByteArray("propertyReset(QString)"));
+ QList<QByteArray> paramsReset;
+ paramsReset << QByteArray("name");
+ resetProp.setParameterNames(paramsReset);
+
+
+ // Add our properties/enums
+ int propCount = d->serviceMeta->propertyCount();
+ for (int i=0; i<propCount; i++) {
+ QMetaProperty mp = d->serviceMeta->property(i);
+
+ QMetaPropertyBuilder property = builder.addProperty(mp.name(), mp.typeName());
+ property.setReadable(mp.isReadable());
+ property.setWritable(mp.isWritable());
+ property.setResettable(mp.isResettable());
+ property.setDesignable(mp.isDesignable());
+ property.setScriptable(mp.isScriptable());
+ property.setStored(mp.isStored());
+ property.setEditable(mp.isEditable());
+ property.setUser(mp.isUser());
+ property.setStdCppSet(mp.hasStdCppSet());
+ property.setEnumOrFlag(mp.isEnumType());
+ }
+
+ // Needs Enumerators support when QtDBus supports
+
+ mo = mo->superClass();
+ }
+
+ // return our constructed dbus metaobject
+ return builder.toMetaObject();
+}
+
+/*!
+ Provide custom Q_OBJECT implementation of the metaObject
+*/
+const QMetaObject* QServiceMetaObjectDBus::metaObject() const
+{
+ // Provide our construected DBus service metaobject
+ return d->dbusMeta;
+}
+
+/*!
+ Overrides metacall which relays the DBus service call to the actual service
+ meta object. Positive return will indicate that the metacall was unsuccessful
+*/
+int QServiceMetaObjectDBus::qt_metacall(QMetaObject::Call c, int id, void **a)
+{
+ int dbusIndex = id;
+
+ // Relay the meta-object call to the service object
+ if (c == QMetaObject::InvokeMetaMethod) {
+ // METHOD CALL
+ QMetaMethod method = d->dbusMeta->method(id);
+
+ const bool isSignal = (method.methodType() == QMetaMethod::Signal);
+
+ ///////////////////// CHECK SPECIAL PROPERTY ///////////////////////
+ // This is required because property READ/RESET doesn't function
+ // as desired over DBus without the use of adaptors. Temporary
+ // methods propertyRead and propertyReset are added to the published
+ // meta object and relay the correct property call
+ QString methodName(QLatin1String(method.signature()));
+ methodName.truncate(methodName.indexOf(QLatin1String("(")));
+
+ if (methodName == QLatin1String("propertyRead")) {
+ QString propertyName = *reinterpret_cast<QString*>(a[1]);
+ int index = d->dbusMeta->indexOfProperty(propertyName.toLatin1().constData());
+ id = qt_metacall(QMetaObject::ReadProperty, index, a);
+ return id;
+
+ } else if (methodName == QLatin1String("propertyReset")) {
+ QString propertyName = *reinterpret_cast<QString*>(a[1]);
+ int index = d->dbusMeta->indexOfProperty(propertyName.toLatin1().constData());
+ id = qt_metacall(QMetaObject::ResetProperty, index, a);
+ return id;
+ }
+ ////////////////////////////////////////////////////////////////////
+
+ // Find the corresponding signature to our service object
+ QByteArray sig(method.signature());
+ int count = methodName.size() + 1;
+ const QList<QByteArray> xTypes = method.parameterTypes();
+ const int xTypesCount = xTypes.count();
+ for (int i=0; i < xTypesCount; i++) {
+ const QByteArray& t = xTypes[i];
+ int variantType = QVariant::nameToType(t);
+ if (variantType == QVariant::UserType) {
+ variantType = QMetaType::type(t);
+ }
+
+ // Check for QVariants or custom types, represented as QDBusVariants
+ if (t == "QDBusVariant") {
+ // Convert QDBusVariant to QVariant
+ QVariant convert = QVariant(variantType, a[i+1]);
+ QDBusVariant dbusVariant = qvariant_cast<QDBusVariant>(convert);
+ QVariant variant = dbusVariant.variant();
+
+ // Is a custom argument if castable to QDBusArgument
+ bool hasCustomType = variant.canConvert<QDBusArgument>();
+ QByteArray replacement("QVariant");
+
+ // Custom types will have QDBusArgument streaming operators for
+ // the QServiceUserTypeDBus object. Extract the real type name
+ // and buffered QVariant from this
+ if (hasCustomType) {
+ QDBusArgument demarshall = variant.value<QDBusArgument>();
+ QServiceUserTypeDBus userType = qdbus_cast<QServiceUserTypeDBus>(demarshall);
+ *reinterpret_cast<QVariant*>(a[i+1]) = userType.variantBuffer;
+
+ replacement = userType.typeName;
+ }
+
+ // Replace "QDBusVariant" with "QVariant" or custom type name
+ sig.replace(count, 12, replacement);
+ count += replacement.size();
+
+ } else {
+ // Supported type so skip this paramater
+ count += t.size();
+ }
+
+ // Skips the comma if not last parameter
+ if (i < xTypesCount)
+ count += 1;
+ }
+
+ // Find the corresponding method metaindex to our service object
+ id = d->serviceMeta->indexOfMethod(sig);
+ QMetaMethod mm = d->serviceMeta->method(id);
+
+ const QList<QByteArray> pTypes = mm.parameterTypes();
+ const int pTypesCount = pTypes.count();
+
+ const char* typeNames[] = {0,0,0,0,0,0,0,0,0,0};
+ const void* params[] = {0,0,0,0,0,0,0,0,0,0};
+ bool hasCustomType = false;
+
+ // Process arguments
+ for (int i=0; i < pTypesCount; i++) {
+ const QByteArray& t = pTypes[i];
+ int variantType = QVariant::nameToType(t);
+ if (variantType == QVariant::UserType) {
+ variantType = QMetaType::type(t);
+ }
+
+ if (variantType >= QMetaType::User) {
+ // Custom argument
+ QVariant convert = QVariant(QVariant::ByteArray, a[i+1]);
+ QByteArray buffer = convert.toByteArray();
+ QDataStream stream(&buffer, QIODevice::ReadWrite);
+
+ // Load our buffered variant-wrapped custom type
+ QVariant *customType = new QVariant(variantType, (const void*)0);
+ QMetaType::load(stream, QMetaType::type("QVariant"), customType);
+
+ typeNames[i] = customType->typeName();
+ params[i] = customType->constData();
+ hasCustomType = true;
+ }
+ }
+
+ // Check if this is a signal emit and activate
+ if (isSignal) {
+ QMetaObject::activate(this, dbusIndex, a);
+ return id;
+ }
+
+ // Check for custom return types and make the metacall
+ const QByteArray& type = mm.typeName();
+ int retType = QVariant::nameToType(type);
+ retType = QMetaType::type(type);
+ if (retType >= QMetaType::User) {
+ // Invoke the object method directly for custom return types
+ bool result = false;
+ QVariant returnValue = QVariant(retType, (const void*)0);
+ QGenericReturnArgument ret(type, returnValue.data());
+ result = mm.invoke(d->service, ret,
+ QGenericArgument(typeNames[0], params[0]),
+ QGenericArgument(typeNames[1], params[1]),
+ QGenericArgument(typeNames[2], params[2]),
+ QGenericArgument(typeNames[3], params[3]),
+ QGenericArgument(typeNames[4], params[4]),
+ QGenericArgument(typeNames[5], params[5]),
+ QGenericArgument(typeNames[6], params[6]),
+ QGenericArgument(typeNames[7], params[7]),
+ QGenericArgument(typeNames[8], params[8]),
+ QGenericArgument(typeNames[9], params[9]));
+
+ if (result) {
+ // Wrap custom return type in a QDBusVariant of the type
+ // and a buffer of its variant-wrapped data
+ QByteArray buffer;
+ QDataStream stream(&buffer, QIODevice::WriteOnly | QIODevice::Append);
+ stream << returnValue;
+
+ QServiceUserTypeDBus customType;
+ customType.typeName = type;
+ customType.variantBuffer = buffer;
+
+ QDBusVariant replacement(QVariant::fromValue(customType));
+ *reinterpret_cast<QDBusVariant*>(a[0]) = replacement;
+
+ // Return negative id to say metacall was handled externally
+ return -1;
+ }
+
+ } else {
+ // Void or standard return types
+ if (hasCustomType == true) {
+ // Invoke the object method directly for custom arguments
+ bool result = false;
+ result = mm.invoke(d->service,
+ QGenericArgument(typeNames[0], params[0]),
+ QGenericArgument(typeNames[1], params[1]),
+ QGenericArgument(typeNames[2], params[2]),
+ QGenericArgument(typeNames[3], params[3]),
+ QGenericArgument(typeNames[4], params[4]),
+ QGenericArgument(typeNames[5], params[5]),
+ QGenericArgument(typeNames[6], params[6]),
+ QGenericArgument(typeNames[7], params[7]),
+ QGenericArgument(typeNames[8], params[8]),
+ QGenericArgument(typeNames[9], params[9]));
+ if (result) {
+ // Return negative id to say metacall was handled externally
+ return -1;
+ }
+ } else {
+ // Relay standard metacall to service object
+ id = d->service->qt_metacall(c, id, a);
+ }
+ }
+
+ } else {
+ // PROPERTY CALL
+
+ // Find the corresponding property metaindex of our service object
+ QMetaProperty property = d->dbusMeta->property(id);
+ QByteArray name(property.name());
+ id = d->serviceMeta->indexOfProperty(name);
+
+ if (c == QMetaObject::ReadProperty) {
+ // Convert to DBusVariant
+ QMetaProperty mp = d->serviceMeta->property(id);
+ QVariant value = mp.read(d->service);
+ QDBusVariant replacement(value);
+ *reinterpret_cast<QDBusVariant*>(a[0]) = replacement;
+
+ // Return negative id to say metacall was handled externally
+ return -1;
+ }
+
+ // Metacall our service object property
+ id = d->service->qt_metacall(c, id, a);
+ }
+
+ return id;
+}
+
+void *QServiceMetaObjectDBus::qt_metacast(const char* className)
+{
+ if (!className) return 0;
+ //this object should not be castable to anything but QObject
+ return QObject::qt_metacast(className);
+}
+
+QDBusArgument &operator<<(QDBusArgument &argument, const QServiceUserTypeDBus &myType)
+{
+ argument.beginStructure();
+ argument << myType.typeName << myType.variantBuffer;
+ argument.endStructure();
+ return argument;
+}
+
+const QDBusArgument &operator>>(const QDBusArgument &argument, QServiceUserTypeDBus &myType)
+{
+ argument.beginStructure();
+ argument >> myType.typeName >> myType.variantBuffer;
+ argument.endStructure();
+ return argument;
+}
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/qservicemetaobject_dbus_p.h b/src/serviceframework/ipc/qservicemetaobject_dbus_p.h
new file mode 100644
index 00000000..17490456
--- /dev/null
+++ b/src/serviceframework/ipc/qservicemetaobject_dbus_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERVICE_METAOBJECT_DBUS_H
+#define QSERVICE_METAOBJECT_DBUS_H
+
+#include "qserviceframeworkglobal.h"
+#include "objectendpoint_dbus_p.h"
+#include <QObject>
+
+QTM_BEGIN_NAMESPACE
+
+class QServiceMetaObjectDBusPrivate;
+class QServiceMetaObjectDBus : public QDBusAbstractAdaptor
+{
+
+public:
+ QServiceMetaObjectDBus(QObject* service, bool signalsObject=false);
+ virtual ~QServiceMetaObjectDBus();
+
+ virtual const QMetaObject* metaObject() const;
+ int qt_metacall(QMetaObject::Call c, int id, void **a);
+ void *qt_metacast(const char* className);
+
+ void activateMetaSignal(int id, const QVariantList& args);
+
+protected:
+ //void connectNotify(const char* signal);
+ //void disconnectNotify(const char* signal);
+
+private:
+ const QMetaObject* dbusMetaObject(bool signalsObject) const;
+ void connectMetaSignals(bool signalsObject);
+
+ QServiceMetaObjectDBusPrivate* d;
+ QVector<bool> localSignals;
+};
+
+
+struct QServiceUserTypeDBus
+{
+ QByteArray typeName;
+ QByteArray variantBuffer;
+};
+
+QDBusArgument &operator<<(QDBusArgument &argument, const QServiceUserTypeDBus &myType);
+const QDBusArgument &operator>>(const QDBusArgument &argument, QServiceUserTypeDBus &myType);
+
+QTM_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QTM_PREPEND_NAMESPACE(QServiceUserTypeDBus))
+
+#endif //QSERVICE_METAOBJECT_DBUS_H
diff --git a/src/serviceframework/ipc/qservicepackage.cpp b/src/serviceframework/ipc/qservicepackage.cpp
new file mode 100644
index 00000000..6a9429a4
--- /dev/null
+++ b/src/serviceframework/ipc/qservicepackage.cpp
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qservicepackage_p.h"
+#include <QDebug>
+
+QTM_BEGIN_NAMESPACE
+
+QServicePackage::QServicePackage()
+ : d(0)
+{
+
+}
+
+QServicePackage::QServicePackage(const QServicePackage& other)
+ : d(other.d)
+{
+}
+
+QServicePackage& QServicePackage::operator=(const QServicePackage& other)
+{
+ d = other.d;
+ return *this;
+}
+
+QServicePackage::~QServicePackage()
+{
+}
+
+bool QServicePackage::isValid() const
+{
+ return d;
+}
+
+QServicePackage QServicePackage::createResponse() const
+{
+ Q_ASSERT(d->responseType == QServicePackage::NotAResponse);
+ QServicePackage response;
+ response.d = new QServicePackagePrivate();
+ response.d->packageType = d->packageType;
+ response.d->messageId = d->messageId;
+ response.d->instanceId = d->instanceId;
+ response.d->responseType = QServicePackage::Failed;
+
+ return response;
+}
+
+#ifndef QT_NO_DATASTREAM
+QDataStream &operator<<(QDataStream &out, const QServicePackage& package)
+{
+ const quint32 magicNumber = 0x78AFAFB;
+ out.setVersion(QDataStream::Qt_4_6);
+ out << magicNumber;
+
+ const qint8 valid = package.d ? 1 : 0;
+ out << (qint8) valid;
+ if (valid) {
+ out << (qint8) package.d->packageType;
+ out << (qint8) package.d->responseType;
+ out << package.d->messageId;
+ out << package.d->instanceId;
+ out << package.d->entry;
+ out << package.d->payload;
+ }
+
+ return out;
+}
+
+QDataStream &operator>>(QDataStream &in, QServicePackage& package)
+{
+ const quint32 magicNumber = 0x78AFAFB;
+ in.setVersion(QDataStream::Qt_4_6);
+
+ quint32 storedMagicNumber;
+ in >> storedMagicNumber;
+ if (storedMagicNumber != magicNumber) {
+ qWarning() << "Datastream doesn't provide serialized QServiceFilter";
+ return in;
+ }
+
+ qint8 valid;
+ in >> valid;
+ if (valid) {
+ if (!package.d) {
+ QServicePackagePrivate* priv = new QServicePackagePrivate();
+ package.d = priv;
+ } else {
+ package.d.detach();
+ package.d->clean();
+ }
+ qint8 data;
+ in >> data;
+ package.d->packageType = (QServicePackage::Type) data;
+ in >> data;
+ package.d->responseType = (QServicePackage::ResponseType) data;
+ in >> package.d->messageId;
+ in >> package.d->instanceId;
+ in >> package.d->entry;
+ in >> package.d->payload;
+ } else {
+ if (package.d)
+ package.d.reset();
+ }
+
+ return in;
+}
+#endif
+
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QServicePackage& p)
+{
+ if (p.isValid()) {
+ QString type;
+ switch (p.d->packageType) {
+ case QServicePackage::ObjectCreation:
+ type = QLatin1String("ObjectCreation");
+ break;
+ case QServicePackage::MethodCall:
+ type = QLatin1String("MethodCall");
+ break;
+ case QServicePackage::PropertyCall:
+ type = QLatin1String("PropertyCall");
+ break;
+ default:
+ break;
+ }
+ dbg.nospace() << "QServicePackage ";
+ dbg.nospace() << type << " " << p.d->responseType ; dbg.space();
+ dbg.nospace() << p.d->messageId; dbg.space();
+ dbg.nospace() << p.d->entry;dbg.space();
+ } else {
+ dbg.nospace() << "QServicePackage(invalid)";
+ }
+ return dbg.space();
+}
+#endif
+
+
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/qservicepackage_p.h b/src/serviceframework/ipc/qservicepackage_p.h
new file mode 100644
index 00000000..0801e437
--- /dev/null
+++ b/src/serviceframework/ipc/qservicepackage_p.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERVICE_PACKAGE_H
+#define QSERVICE_PACKAGE_H
+
+#include "qserviceframeworkglobal.h"
+#include <QExplicitlySharedDataPointer>
+#include <QSharedData>
+#include <QUuid>
+#include <QVariant>
+#include "qremoteserviceregister.h"
+
+QT_BEGIN_NAMESPACE
+class QDataStream;
+class QDebug;
+QT_END_NAMESPACE
+
+QTM_BEGIN_NAMESPACE
+
+class QServicePackagePrivate;
+class Q_AUTOTEST_EXPORT QServicePackage
+{
+public:
+ QServicePackage();
+ QServicePackage(const QServicePackage& other);
+ QServicePackage& operator=(const QServicePackage& other);
+ ~QServicePackage();
+
+ enum Type {
+ ObjectCreation = 0,
+ MethodCall,
+ PropertyCall
+ };
+
+ enum ResponseType {
+ NotAResponse = 0,
+ Success,
+ Failed
+ };
+
+ QServicePackage createResponse() const;
+
+ bool isValid() const;
+
+ QExplicitlySharedDataPointer<QServicePackagePrivate> d;
+
+#ifndef QT_NO_DATASTREAM
+ friend QDataStream &operator<<(QDataStream &, const QServicePackage&);
+ friend QDataStream &operator>>(QDataStream &, QServicePackage&);
+#endif
+};
+
+#ifndef QT_NO_DATASTREAM
+QDataStream &operator<<(QDataStream &, const QServicePackage&);
+QDataStream &operator>>(QDataStream &, QServicePackage&);
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug, const QServicePackage&);
+#endif
+
+class QServicePackagePrivate : public QSharedData
+{
+public:
+ QServicePackagePrivate()
+ : packageType(QServicePackage::ObjectCreation),
+ entry(QRemoteServiceRegister::Entry()), payload(QVariant()),
+ messageId(QUuid()), instanceId(QUuid()), responseType(QServicePackage::NotAResponse)
+ {
+ }
+
+ QServicePackage::Type packageType;
+ QRemoteServiceRegister::Entry entry;
+ QVariant payload;
+ QUuid messageId;
+ QUuid instanceId;
+ QServicePackage::ResponseType responseType;
+
+ virtual void clean()
+ {
+ packageType = QServicePackage::ObjectCreation;
+ messageId = QUuid();
+ instanceId = QUuid();
+ payload = QVariant();
+ entry = QRemoteServiceRegister::Entry();
+ responseType = QServicePackage::NotAResponse;
+ }
+};
+
+QTM_END_NAMESPACE
+
+#endif
diff --git a/src/serviceframework/ipc/qsignalintercepter.cpp b/src/serviceframework/ipc/qsignalintercepter.cpp
new file mode 100644
index 00000000..ba8a5ebf
--- /dev/null
+++ b/src/serviceframework/ipc/qsignalintercepter.cpp
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qsignalintercepter_p.h"
+#include <qmetaobject.h>
+#include <qmetatype.h>
+#include <qobjectdefs.h>
+#include <qdebug.h>
+
+/*!
+ \class QSignalIntercepter
+ \inpublicgroup QtBaseModule
+ \internal
+
+ \brief The QSignalIntercepter class provides an interface for intercepting signals as meta-calls
+ \since 1.1
+
+ IPC mechanisms need to intercept signals and convert them into protocol
+ messages, but it is generally impractical to create a slot for every
+ signal that needs to be dispatched. The QSignalIntercepter class allows
+ signals to be intercepted as meta-calls so that IPC dispatching can
+ be implemented in a generic fashion.
+
+ The activated() method is called whenever the signal is emitted,
+ with the arguments in a typed list.
+
+ \sa QSlotInvoker
+
+ \ingroup objectmodel
+*/
+
+QTM_BEGIN_NAMESPACE
+
+class QSignalIntercepterPrivate
+{
+public:
+ QObject *sender;
+ QByteArray signal;
+ int signalIndex;
+ int destroyIndex;
+ int slotIndex;
+ int *types;
+ int numArgs;
+
+ ~QSignalIntercepterPrivate()
+ {
+ if ( types )
+ qFree( types );
+ }
+};
+
+/*!
+ Create a new signal intercepter which traps \a signal on \a sender.
+ The object will be attached to \a parent, if present.
+ \since 1.1
+*/
+QSignalIntercepter::QSignalIntercepter
+ ( QObject *sender, const QByteArray& signal, QObject *parent )
+ : QObject( parent )
+{
+ // Initialize the private members.
+ d = new QSignalIntercepterPrivate();
+ d->sender = sender;
+ d->signal = signal;
+ d->signalIndex = -1;
+ d->destroyIndex = -1;
+ d->slotIndex = -1;
+ d->types = 0;
+
+ // Resolve the indices of the signals we are interested in.
+ if ( sender && signal.size() > 0 ) {
+ // '2' is QSIGNAL_CODE in Qt 4.4 and below,
+ // '6' is QSIGNAL_CODE in Qt 4.5 and higher.
+ if ( signal[0] != '2' && signal[0] != '6' ) {
+ qWarning( "QSignalIntercepter: `%s' is not a valid signal "
+ "specification", signal.constData() );
+ return;
+ }
+ QByteArray name = QMetaObject::normalizedSignature
+ ( signal.constData() + 1 );
+ d->signalIndex
+ = sender->metaObject()->indexOfSignal( name.constData() );
+ if ( d->signalIndex < 0 ) {
+ qWarning( "QSignalIntercepter: no such signal: %s::%s",
+ sender->metaObject()->className(), signal.constData() );
+ return;
+ }
+ d->destroyIndex
+ = sender->metaObject()->indexOfSignal( "destroyed()" );
+ d->types = connectionTypes( name, d->numArgs );
+ }
+
+ // Derive a fake slot index to use in our manual qt_metacall implementation.
+ d->slotIndex = staticMetaObject.methodCount();
+
+ // Connect up the signals.
+ if ( d->signalIndex >= 0 ) {
+ QMetaObject::connect( sender, d->signalIndex,
+ this, d->slotIndex,
+ Qt::DirectConnection, 0 );
+ }
+ if ( d->destroyIndex >= 0 ) {
+ QMetaObject::connect( sender, d->destroyIndex,
+ this, d->slotIndex + 1,
+ Qt::DirectConnection, 0 );
+ }
+}
+
+/*!
+ Destroy a signal intercepter.
+*/
+QSignalIntercepter::~QSignalIntercepter()
+{
+ if ( d->signalIndex >= 0 ) {
+ QMetaObject::disconnect( d->sender, d->signalIndex,
+ this, d->slotIndex );
+ }
+ if ( d->destroyIndex >= 0 ) {
+ QMetaObject::disconnect( d->sender, d->destroyIndex,
+ this, d->slotIndex + 1 );
+ }
+ delete d;
+}
+
+/*!
+ Returns the sender that this signal interceptor is attached to.
+ \since 1.1
+*/
+QObject *QSignalIntercepter::sender() const
+{
+ return d->sender;
+}
+
+/*!
+ Returns the name of the signal that this signal interceptor is attached to.
+ \since 1.1
+*/
+QByteArray QSignalIntercepter::signal() const
+{
+ return d->signal;
+}
+
+/*!
+ Returns true if this signal intercepter is valid; that is, there was
+ a signal present with the specified parameters when this object
+ was constructed.
+ \since 1.1
+*/
+bool QSignalIntercepter::isValid() const
+{
+ return ( d->signalIndex != -1 );
+}
+
+/*!
+ \internal
+ \since 1.1
+*/
+int QSignalIntercepter::qt_metacall(QMetaObject::Call c, int id, void **a)
+{
+ id = QObject::qt_metacall(c, id, a);
+ if (id < 0)
+ return id;
+ if (c == QMetaObject::InvokeMetaMethod) {
+ switch (id) {
+ case 0: {
+ // The signal we are interested in has been activated.
+ if ( d->types ) {
+ QList<QVariant> args;
+ for ( int i = 0; i < d->numArgs; ++i ) {
+ if ( d->types[i] != QVariantId ) {
+ QVariant arg( d->types[i], a[i + 1] );
+ args.append( arg );
+ } else {
+ args.append( *((const QVariant *)( a[i + 1] )) );
+ }
+ }
+ activated( args );
+ }
+ }
+ break;
+
+ case 1: {
+ // The sender has been destroyed. Clear the signal indices
+ // so that we don't try to do a manual disconnect when our
+ // own destructor is called.
+ d->signalIndex = -1;
+ d->destroyIndex = -1;
+ }
+ break;
+ }
+ id -= 2;
+ }
+ return id;
+}
+
+/*!
+ \fn void QSignalIntercepter::activated( const QList<QVariant>& args )
+
+ Called when the signal that is being intercepted is activated.
+ The arguments to the signal are passed in the list \a args.
+ \since 1.1
+*/
+
+// Get the QVariant type number for a type name.
+int QSignalIntercepter::typeFromName( const QByteArray& type )
+{
+ int id;
+ if (type.endsWith('*'))
+ return QMetaType::VoidStar;
+ else if ( type.size() == 0 || type == "void" )
+ return QMetaType::Void;
+ else if ( type == "QVariant" )
+ return QSignalIntercepter::QVariantId;
+ id = QMetaType::type( type.constData() );
+ if ( id != (int)QMetaType::Void )
+ return id;
+ return QVariant::nameToType(type);
+}
+
+/*!
+ Returns the connection types associated with a signal or slot \a member
+ specification. The array of types is returned from this function,
+ and the number of arguments is returned in \a nargs. Returns null
+ if \a member is invalid. The return value must be freed with qFree().
+ \since 1.1
+*/
+int *QSignalIntercepter::connectionTypes( const QByteArray& member, int& nargs )
+{
+ // Based on Qt's internal queuedConnectionTypes function.
+ nargs = 0;
+ int *types = 0;
+ const char *s = member.constData();
+ while (*s != '\0' && *s != '(') { ++s; }
+ if ( *s == '\0' )
+ return 0;
+ ++s;
+ const char *e = s;
+ while (*e != ')') {
+ ++e;
+ if (*e == ')' || *e == ',')
+ ++nargs;
+ }
+
+ types = (int *) qMalloc((nargs+1)*sizeof(int));
+ types[nargs] = 0;
+ for (int n = 0; n < nargs; ++n) {
+ e = s;
+ while (*s != ',' && *s != ')')
+ ++s;
+ QByteArray type(e, s-e);
+ ++s;
+
+ types[n] = typeFromName(type);
+ if (!types[n]) {
+ qWarning("QSignalIntercepter::connectionTypes: Cannot marshal arguments of type '%s'", type.data());
+ qFree(types);
+ return 0;
+ }
+ }
+ return types;
+}
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/qsignalintercepter_p.h b/src/serviceframework/ipc/qsignalintercepter_p.h
new file mode 100644
index 00000000..c2661c9f
--- /dev/null
+++ b/src/serviceframework/ipc/qsignalintercepter_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QSIGNALINTERCEPTER_H
+#define QSIGNALINTERCEPTER_H
+
+#include "qserviceframeworkglobal.h"
+#include <qobject.h>
+#include <qvariant.h>
+#include <qlist.h>
+
+QT_BEGIN_HEADER
+
+QTM_BEGIN_NAMESPACE
+
+class QSignalIntercepterPrivate;
+class QSignalIntercepter : public QObject
+{
+ // Note: Do not put Q_OBJECT here.
+ friend class QSlotInvoker;
+ friend class QCopProxy;
+public:
+ QSignalIntercepter( QObject *sender, const QByteArray& signal,
+ QObject *parent=0 );
+ ~QSignalIntercepter();
+
+ QObject *sender() const;
+ QByteArray signal() const;
+
+ bool isValid() const;
+
+ static const int QVariantId = -243;
+
+ static int *connectionTypes( const QByteArray& member, int& nargs );
+
+protected:
+ int qt_metacall( QMetaObject::Call c, int id, void **a );
+ virtual void activated( const QList<QVariant>& args ) = 0;
+
+private:
+ QSignalIntercepterPrivate *d;
+
+ static int typeFromName( const QByteArray& name );
+};
+
+QTM_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/serviceframework/ipc/qslotinvoker.cpp b/src/serviceframework/ipc/qslotinvoker.cpp
new file mode 100644
index 00000000..3c1bb456
--- /dev/null
+++ b/src/serviceframework/ipc/qslotinvoker.cpp
@@ -0,0 +1,269 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qslotinvoker_p.h"
+#include "qsignalintercepter_p.h"
+#include <qmetaobject.h>
+#include <qmetatype.h>
+#include <qvarlengtharray.h>
+
+/*!
+ \class QSlotInvoker
+ \inpublicgroup QtBaseModule
+ \internal
+
+ \brief The QSlotInvoker class provides an interface for invoking slots with explicit arguments
+ \since 1.1
+
+ IPC mechanisms need to intercept protocol messages and convert them into
+ slot invocations, but it is generally impractical to create explicit code
+ for every slot that needs to be dispatched. The QSlotInvoker class allows
+ an IPC dispatching mechanism to invoke slots in a generic fashion using
+ the invoke() method.
+
+ Methods that are marked with Q_INVOKABLE or Q_SCRIPTABLE can also
+ be invoked with this class.
+
+ \sa QSignalIntercepter
+
+ \ingroup objectmodel
+*/
+
+QTM_BEGIN_NAMESPACE
+
+class QSlotInvokerPrivate
+{
+public:
+ QObject *receiver;
+ QByteArray member;
+ int memberIndex;
+ bool destroyed;
+ int returnType;
+ int *types;
+ int numArgs;
+
+ ~QSlotInvokerPrivate()
+ {
+ if ( types )
+ qFree( types );
+ }
+};
+
+/*!
+ Create a slot invoker that can invoke \a member on \a receiver.
+ The object will be attached to \a parent, if present.
+ \since 1.1
+*/
+QSlotInvoker::QSlotInvoker( QObject *receiver, const QByteArray &member,
+ QObject *parent )
+ : QObject( parent )
+{
+ d = new QSlotInvokerPrivate();
+ d->receiver = receiver;
+ QByteArray name;
+ if ( member.size() > 0 && member[0] >= '0' && member[0] <= '9' ) {
+ // Strip off the member type code.
+ name = member.mid(1);
+ } else {
+ name = member;
+ }
+ name = QMetaObject::normalizedSignature( name.constData() );
+ d->member = name;
+ d->destroyed = false;
+ d->returnType = 0;
+ d->types = 0;
+ d->numArgs = 0;
+ if ( receiver && name.size() > 0 ) {
+ d->memberIndex
+ = receiver->metaObject()->indexOfMethod( name.constData() );
+ } else {
+ d->memberIndex = -1;
+ }
+ if ( d->memberIndex != -1 ) {
+ QMetaMethod method = receiver->metaObject()->method
+ ( d->memberIndex );
+ {
+ connect( receiver, SIGNAL(destroyed()),
+ this, SLOT(receiverDestroyed()) );
+ d->returnType =
+ QSignalIntercepter::typeFromName( method.typeName() );
+ d->types = QSignalIntercepter::connectionTypes
+ ( name, d->numArgs );
+ if ( !( d->types ) )
+ d->destroyed = true;
+ }
+ } else {
+ d->destroyed = true;
+ }
+}
+
+/*!
+ Destroy a slot invoker.
+*/
+QSlotInvoker::~QSlotInvoker()
+{
+ delete d;
+}
+
+/*!
+ Returns true if the member is present on the object.
+ \since 1.1
+*/
+bool QSlotInvoker::memberPresent() const
+{
+ return ! d->destroyed;
+}
+
+/*!
+ Returns true if the member can be invoked with \a numArgs arguments.
+ That is, the receiver has not been destroyed, the member is present,
+ and it requires \a numArgs or less arguments.
+ \since 1.1
+*/
+bool QSlotInvoker::canInvoke( int numArgs ) const
+{
+ if ( d->destroyed )
+ return false;
+ return ( numArgs >= d->numArgs );
+}
+
+/*!
+ Returns the object that will receive slot invocations.
+ \since 1.1
+*/
+QObject *QSlotInvoker::receiver() const
+{
+ return d->receiver;
+}
+
+/*!
+ Returns the member that will receiver slot invocations.
+ \since 1.1
+*/
+QByteArray QSlotInvoker::member() const
+{
+ return d->member;
+}
+
+/*!
+ Returns the parameter types associated with this member.
+ \since 1.1
+*/
+int *QSlotInvoker::parameterTypes() const
+{
+ return d->types;
+}
+
+/*!
+ Returns the number of parameter types associated with this member.
+ \since 1.1
+*/
+int QSlotInvoker::parameterTypesCount() const
+{
+ return d->numArgs;
+}
+
+/*!
+ Invokes the slot represented by this object with the argument
+ list \a args. The slot's return value is returned from
+ this method. If the slot's return type is "void", then a
+ QVariant instance of type QVariant::Invalid will be returned.
+
+ If it is possible that the slot may throw an exception,
+ it is the responsibility of the caller to catch and
+ handle the exception.
+ \since 1.1
+*/
+QVariant QSlotInvoker::invoke( const QList<QVariant>& args )
+{
+ int arg;
+ QVariant returnValue;
+
+ // Create a default instance of the return type for the result buffer.
+ if ( d->returnType != (int)QVariant::Invalid ) {
+ returnValue = QVariant( d->returnType, (const void *)0 );
+ }
+
+ // Bail out if the receiver object has already disappeared.
+ if ( d->destroyed )
+ return returnValue;
+
+ // Check that the number of arguments is compatible with the slot.
+ int numArgs = args.size();
+ if ( numArgs < d->numArgs ) {
+ qWarning( "QSlotInvoker::invoke: insufficient arguments for slot" );
+ return returnValue;
+ } else if ( numArgs > d->numArgs ) {
+ // Drop extraneous arguments.
+ numArgs = d->numArgs;
+ }
+
+ // Construct the raw argument list.
+ QVarLengthArray<void *, 32> a( numArgs + 1 );
+ if ( d->returnType == (int)QVariant::Invalid )
+ a[0] = 0;
+ else
+ a[0] = returnValue.data();
+ for ( arg = 0; arg < numArgs; ++arg ) {
+ if ( d->types[arg] == QSignalIntercepter::QVariantId ) {
+ a[arg + 1] = (void *)&( args[arg] );
+ } else if ( args[arg].userType() != d->types[arg] ) {
+ qWarning( "QSlotInvoker::invoke: argument %d has incorrect type",
+ arg );
+ return QVariant();
+ } else {
+ a[arg + 1] = (void *)( args[arg].data() );
+ }
+ }
+
+ // Invoke the specified slot.
+ d->receiver->qt_metacall( QMetaObject::InvokeMetaMethod,
+ d->memberIndex, a.data() );
+ return returnValue;
+}
+
+void QSlotInvoker::receiverDestroyed()
+{
+ d->destroyed = true;
+}
+
+#include "moc_qslotinvoker_p.cpp"
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/qslotinvoker_p.h b/src/serviceframework/ipc/qslotinvoker_p.h
new file mode 100644
index 00000000..69b3c623
--- /dev/null
+++ b/src/serviceframework/ipc/qslotinvoker_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QSLOTINVOKER_H
+#define QSLOTINVOKER_H
+
+#include "qserviceframeworkglobal.h"
+#include <qobject.h>
+#include <qvariant.h>
+#include <qlist.h>
+
+QT_BEGIN_HEADER
+
+QTM_BEGIN_NAMESPACE
+class QSlotInvokerPrivate;
+class QSlotInvoker : public QObject
+{
+ Q_OBJECT
+public:
+ QSlotInvoker( QObject *receiver, const QByteArray& member,
+ QObject *parent=0 );
+ ~QSlotInvoker();
+
+ bool memberPresent() const;
+ bool canInvoke( int numArgs ) const;
+ QObject *receiver() const;
+ QByteArray member() const;
+ int *parameterTypes() const;
+ int parameterTypesCount() const;
+
+public slots:
+ QVariant invoke( const QList<QVariant>& args );
+
+private slots:
+ void receiverDestroyed();
+
+private:
+ QSlotInvokerPrivate *d;
+};
+
+QTM_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/serviceframework/qabstractsecuritysession.cpp b/src/serviceframework/qabstractsecuritysession.cpp
new file mode 100644
index 00000000..d68a5c40
--- /dev/null
+++ b/src/serviceframework/qabstractsecuritysession.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qabstractsecuritysession.h"
+
+QTM_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractSecuritySession
+ \inmodule QtServiceFramework
+ \ingroup servicefw
+ \brief The QAbstractSecuritySession class provides a generic mechanism to enable
+ permission checks for services.
+ \since 1.0
+
+ QAbstractSecuritySession describes the abstract interface that security/permission
+ engines must implement in order to provide capability related functionality.
+
+ A QAbstractSecuritySession encapsulates the service client's capabilities. QServiceManager
+ can match those capabilites with the capabilites required by a particular service.
+ Service capabilites are declared via the services XML description.
+
+ The use of a security session is not mandated by the service manager. If the client
+ is passing a security session object QServiceManager ensures that the permissions
+ are checked before the requested service is loaded and forwards the session to the
+ service in case the service intends to implement additional checks. If no security
+ session is passed to QServiceManager capability checks are not performed. Note that
+ the security session is no substitute for platform security such as control over
+ a processes ability to load arbitrary plug-ins.
+
+ Since the service loader controls whether a security session is passed to the
+ QServiceManager instance it is assumed that the calling context can be trusted. Possible
+ use cases for a security session could be arbitrary Javascript applications which run
+ within a trusted browser environment. The QAbstractSecuritySession interface would allow
+ the browser to provide access to platform services while at the same time being able to
+ ensure that certain Javascript application (depending on e.g their context, URL or signatures)
+ can not access more sensitive system services.
+
+ Framework clients with purely native code bases are likely to never have any security sessions.
+
+ \sa QServiceManager, QServicePluginInterface
+*/
+
+/*!
+ Constructs an abstract security session with the given \a parent.
+*/
+QAbstractSecuritySession::QAbstractSecuritySession(QObject* parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ Destroys the abstract security session.
+*/
+QAbstractSecuritySession::~QAbstractSecuritySession()
+{
+}
+
+/*!
+ \fn bool QAbstractSecuritySession::isAllowed(const QStringList& capabilities) = 0;
+
+ Returns true if the security session has sufficient rights to access the required
+ service \a capabilities.
+ \since 1.0
+*/
+
+#include "moc_qabstractsecuritysession.cpp"
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/qabstractsecuritysession.h b/src/serviceframework/qabstractsecuritysession.h
new file mode 100644
index 00000000..a33c39d6
--- /dev/null
+++ b/src/serviceframework/qabstractsecuritysession.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QABSTRACTSECURITYSESSION_H
+#define QABSTRACTSECURITYSESSION_H
+
+#include "qserviceframeworkglobal.h"
+#include <QObject>
+
+QT_BEGIN_HEADER
+
+QTM_BEGIN_NAMESPACE
+
+class Q_SERVICEFW_EXPORT QAbstractSecuritySession : public QObject
+{
+ Q_OBJECT
+public:
+ QAbstractSecuritySession(QObject* parent = 0);
+ virtual ~QAbstractSecuritySession();
+
+ virtual bool isAllowed(const QStringList& capabilityList) = 0;
+};
+
+QTM_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //QABSTRACTSECURITYSESSION_H
+
diff --git a/src/serviceframework/qremoteserviceregister.cpp b/src/serviceframework/qremoteserviceregister.cpp
new file mode 100644
index 00000000..0ce330f3
--- /dev/null
+++ b/src/serviceframework/qremoteserviceregister.cpp
@@ -0,0 +1,461 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qremoteserviceregister.h"
+#include "qremoteserviceregisterentry_p.h"
+#include "ipc/instancemanager_p.h"
+#include "qremoteserviceregister_p.h"
+
+QTM_BEGIN_NAMESPACE
+
+/*!
+ \class QRemoteServiceRegister::Entry
+ \ingroup servicefw
+ \inmodule QtServiceFramework
+ \brief The Entry class represents a remote service entry to be published on QRemoteServiceRegister.
+
+ This class is created using QRemoteServiceRegister::createEntry to supply remote service
+ details matching a valid QServiceInterfaceDescriptor.
+
+ A registration entry can then be published for discovery by remote clients.
+
+ \since 1.1
+*/
+
+/*!
+ Constructs a null registration entry.
+ \since 1.1
+*/
+QRemoteServiceRegister::Entry::Entry()
+{
+ d = new QRemoteServiceRegisterEntryPrivate;
+}
+
+/*!
+ Constructs the registration entry that is a copy of \a other.
+ \since 1.1
+*/
+QRemoteServiceRegister::Entry::Entry(const Entry& other)
+ : d(other.d)
+{
+}
+
+/*!
+ Destroys the registration entry.
+ \since 1.1
+*/
+QRemoteServiceRegister::Entry::~Entry()
+{
+}
+
+/*!
+ Checks if the registration entry is currently a valid remote service entry
+
+ Returns true if the serviceName(), interfaceName() and version() point to
+ a valid QServiceInterfaceDescriptor, otherwise false.
+ \since 1.1
+*/
+bool QRemoteServiceRegister::Entry::isValid() const
+{
+ if (!d->iface.isEmpty() && !d->service.isEmpty()
+ && !d->ifaceVersion.isEmpty() && d->cptr!=0 && d->meta!=0)
+ return true;
+ return false;
+}
+
+/*!
+ Returns true if this font is equal to \a other; otherwise false.
+ \since 1.1
+*/
+bool QRemoteServiceRegister::Entry::operator==(const Entry& other) const
+{
+ return d->service == other.d->service &&
+ d->iface == other.d->iface &&
+ d->ifaceVersion == other.d->ifaceVersion;
+}
+
+/*!
+ Returns true if this font is different from \a other; otherwise false.
+ \since 1.1
+*/
+bool QRemoteServiceRegister::Entry::operator!=(const Entry& other) const
+{
+ return !(other == *this);
+}
+
+/*!
+ Assigns \a other to this registration entry and returns a reference to it.
+ \since 1.1
+*/
+QRemoteServiceRegister::Entry &QRemoteServiceRegister::Entry::operator=(const Entry& other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Returns the interface name of the registration entry.
+
+ This should correspond to the interface name from the service XML description.
+
+ \sa serviceName(), version()
+ \since 1.1
+*/
+QString QRemoteServiceRegister::Entry::interfaceName() const
+{
+ return d->iface;
+}
+
+/*!
+ Returns the service name of the registration entry.
+
+ This should correspond to the service name from the service XML description.
+
+ \sa interfaceName(), version()
+ \since 1.1
+*/
+QString QRemoteServiceRegister::Entry::serviceName() const
+{
+ return d->service;
+}
+
+/*!
+ Returns the version of the registration entry in format x.y.
+
+ This should correspond to the interface version from the service XML description.
+
+ \sa interfaceName(), serviceName()
+ \since 1.1
+*/
+QString QRemoteServiceRegister::Entry::version() const
+{
+ return d->ifaceVersion;
+}
+
+const QMetaObject * QRemoteServiceRegister::Entry::metaObject() const
+{
+ return d->meta;
+}
+
+/*!
+ Sets the QRemoteServiceRegister::InstanceType of the registration entry.
+
+ If this is not explicitly called, the default instance \a type for the registration entry
+ is QRemoteServiceRegister::PrivateInstance.
+ \since 1.1
+*/
+void QRemoteServiceRegister::Entry::setInstantiationType(QRemoteServiceRegister::InstanceType type)
+{
+ d->instanceType = type;
+}
+
+/*!
+ Returns the QRemoteServiceRegister::InstanceType of the registration entry.
+ \since 1.1
+*/
+QRemoteServiceRegister::InstanceType QRemoteServiceRegister::Entry::instantiationType() const
+{
+ return d->instanceType;
+}
+
+/*!
+ \class QRemoteServiceRegister
+ \inmodule QtServiceFramework
+ \ingroup servicefw
+ \brief The QRemoteServiceRegister class manages instances of remote service objects.
+ \since 1.1
+
+ This class registers and publishes IPC based service objects. It owns the service's
+ objects and uess the platform specific IPC mechanism to publish the service.
+
+ In order for the remote services to be discoverable by QServiceManager each
+ QRemoteServiceRegister::Entry must be registered with the same information in
+ the XML description, otherwise no corresponding QServiceInterfaceDescriptor can be
+ found.
+
+ The following XML descriptor is used for subsequent examples.
+
+ \code
+ <SFW version="1.1">
+ <service>
+ <name>MyService</name>
+ <ipcaddress>my_executable</ipcaddress>
+ <description>My service example</description>
+ <interface>
+ <name>com.nokia.qt.example.myService</name>
+ <version>1.0</version>
+ <description>My private service</description>
+ <capabilities></capabilities>
+ </interface>
+ </service>
+ </SFW>
+ \endcode
+
+ The snippet belows demonstrates how an application can register the class \a MyClass
+ as a remote service, which is published and accessible to clients who wish to load
+ service object instances.
+
+ \code
+ int main(int argc, char** argv)
+ {
+ QCoreApplication app(argc, argv);
+
+ QRemoteServiceRegister *serviceRegister = new QRemoteServiceRegister();
+
+ QRemoteServiceRegister::Entry myService;
+ myService = serviceRegister->createEntry<MyClass>(
+ "MyService", "com.nokia.qt.example.myservice", "1.0");
+
+ serviceRegister->publishEntries("my_service");
+
+ return app.exec();
+ delete serviceRegister;
+ }
+ \endcode
+
+ By default all entries are created as \l QRemoteServiceRegister::GlobalInstance
+ types. This can be changed by calling QRemoteServiceRegister::Entry::setInstantiationType()
+ on the entry. Once the service register has been published the associated service entries
+ can no longer be changed.
+
+ \sa QRemoteServiceRegister::Entry
+*/
+
+/*!
+ \enum QRemoteServiceRegister::InstanceType
+ Defines the two types of instances for a registration entry
+ \value GlobalInstance New requests for a service gets the same service instance
+ \value PrivateInstance New requests for a service gets a new service instance
+*/
+
+/*!
+ \fn void QRemoteServiceRegister::instanceClosed(const QRemoteServiceRegister::Entry& entry)
+
+ This signal is emitted whenever a created instance has been closed. This indicates
+ that a connected client has either shutdown or released the loaded service object.
+
+ \a entry is supplied to identify which registered service
+ entry the closed instance belonged to.
+
+ \sa allInstancesClosed()
+ \since 1.1
+*/
+
+/*!
+ \fn void QRemoteServiceRegister::allInstancesClosed()
+
+ This signal is emitted whenever all service instances have been closed. This indicates
+ that the last connected client has either shutdown or released the loaded service object.
+
+ \sa instanceClosed()
+ \since 1.1
+*/
+
+/*!
+ \typedef QRemoteServiceRegister::CreateServiceFunc
+ \internal
+ Denotes a function pointer returning a service instance
+*/
+
+/*!
+ \typedef QRemoteServiceRegister::SecurityFilter
+ \internal
+ Denotes a function pointer used for the security filter feature
+*/
+
+/*!
+ Creates a service register instance with the given \a parent.
+ \since 1.1
+*/
+QRemoteServiceRegister::QRemoteServiceRegister(QObject* parent)
+ : QObject(parent)
+{
+ d = QRemoteServiceRegisterPrivate::constructPrivateObject(this);
+
+ connect(InstanceManager::instance(), SIGNAL(allInstancesClosed()),
+ this, SIGNAL(allInstancesClosed()));
+ connect(InstanceManager::instance(), SIGNAL(instanceClosed(QRemoteServiceRegister::Entry)),
+ this, SIGNAL(instanceClosed(QRemoteServiceRegister::Entry)));
+}
+
+/*!
+ Destroys the service register instance
+*/
+QRemoteServiceRegister::~QRemoteServiceRegister()
+{
+}
+
+/*!
+ Publishes every service QRemoteServiceRegister::Entry that has been created using
+ \l createEntry(). The \a ident is the service specific IPC address under which
+ the service can be reached.
+
+ This address must match the address provided in the services XML descriptor, otherwise
+ the service will not be discoverable. In some cases this may also cause the IPC
+ rendezvous feature to fail.
+
+ \sa createEntry()
+ \since 1.1
+*/
+void QRemoteServiceRegister::publishEntries(const QString& ident)
+{
+ d->publishServices(ident);
+}
+
+/*!
+ \property QRemoteServiceRegister::quitOnLastInstanceClosed
+
+ \brief Terminate the service when all clients have closed all objects. Default value is true.
+ \since 1.1
+*/
+bool QRemoteServiceRegister::quitOnLastInstanceClosed() const
+{
+ return d->quitOnLastInstanceClosed();
+}
+
+void QRemoteServiceRegister::setQuitOnLastInstanceClosed(bool quit)
+{
+ d->setQuitOnLastInstanceClosed(quit);
+}
+
+/*!
+ Allows a security filter to be set which can access
+ QRemoteServiceRegister::QRemoteServiceRegisterCredentials.
+
+ The \a filter is a function pointer where the function code implements possible
+ permission checks and returns true or false. If a connecting client fails the security
+ filter it will be denied access and unable to obtain a valid service instance.
+
+ The following snippet is an example of how to use the security filter feature.
+
+ \code
+ bool myFunction(const void *p)
+ {
+ const QRemoteServiceRegisterCredentials *cred =
+ (const struct QRemoteServiceRegisterCredentials *)p;
+
+ // allow the superuser
+ if (cred->uid == 0)
+ return true;
+
+ return false;
+ }
+
+ int main(int argc, char** argv)
+ {
+ ...
+
+ QRemoteServiceRegister* serviceRegister = new QRemoteServiceRegister();
+ service->setSecurityFilter(myFunction);
+
+ ...
+ }
+ \endcode
+
+ \since 1.1
+*/
+QRemoteServiceRegister::SecurityFilter QRemoteServiceRegister::setSecurityFilter(QRemoteServiceRegister::SecurityFilter filter)
+{
+ return d->setSecurityFilter(filter);
+}
+
+/*!
+ \fn QRemoteServiceRegister::createEntry(const QString& serviceName, const QString& interfaceName, const QString& version)
+
+ Creates an entry on our remote instance manager. The \a serviceName, \a interfaceName and
+ \a version must match the service XML descriptor in order for the remote service to be
+ discoverable.
+
+ \sa publishEntries()
+ \since 1.1
+*/
+QRemoteServiceRegister::Entry QRemoteServiceRegister::createEntry(const QString& serviceName, const QString& interfaceName, const QString& version, QRemoteServiceRegister::CreateServiceFunc cptr, const QMetaObject* meta)
+{
+ if (serviceName.isEmpty()
+ || interfaceName.isEmpty()
+ || version.isEmpty() ) {
+ qWarning() << "QRemoteServiceRegister::registerService: service name, interface name and version must be specified";
+ return Entry();
+ }
+
+ Entry e;
+ e.d->service = serviceName;
+ e.d->iface = interfaceName;
+ e.d->ifaceVersion = version;
+ e.d->cptr = cptr;
+ e.d->meta = meta;
+
+ Q_ASSERT(InstanceManager::instance());
+ InstanceManager::instance()->addType(e);
+
+ return e;
+}
+
+
+#ifndef QT_NO_DATASTREAM
+QDataStream& operator>>(QDataStream& s, QRemoteServiceRegister::Entry& entry) {
+ //for now we only serialize version, iface and service name
+ //needs to sync with qHash and operator==
+ s >> entry.d->service >> entry.d->iface >> entry.d->ifaceVersion;
+ return s;
+}
+
+QDataStream& operator<<(QDataStream& s, const QRemoteServiceRegister::Entry& entry) {
+ //for now we only serialize version, iface and service name
+ //needs to sync with qHash and operator==
+ s << entry.d->service << entry.d->iface << entry.d->ifaceVersion;
+ return s;
+}
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QRemoteServiceRegister::Entry& entry) {
+ dbg.nospace() << "QRemoteServiceRegister::Entry("
+ << entry.serviceName() << ", "
+ << entry.interfaceName() << ", "
+ << entry.version() << ")";
+ return dbg.space();
+}
+#endif
+
+#include "moc_qremoteserviceregister.cpp"
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/qremoteserviceregister.h b/src/serviceframework/qremoteserviceregister.h
new file mode 100644
index 00000000..aa8e6756
--- /dev/null
+++ b/src/serviceframework/qremoteserviceregister.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QREMOTESERVICEREGISTER_H
+#define QREMOTESERVICEREGISTER_H
+
+#include "qserviceframeworkglobal.h"
+#include <QObject>
+#include <QQueue>
+#include <QHash>
+#include <QDebug>
+#include <QExplicitlySharedDataPointer>
+
+QTM_BEGIN_NAMESPACE
+
+class QRemoteServiceRegisterPrivate;
+class QRemoteServiceRegisterEntryPrivate;
+
+class Q_SERVICEFW_EXPORT QRemoteServiceRegister : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool quitOnLastInstanceClosed READ quitOnLastInstanceClosed WRITE setQuitOnLastInstanceClosed)
+public:
+
+ enum InstanceType {
+ GlobalInstance = 0,
+ PrivateInstance
+ };
+
+ typedef QObject *(*CreateServiceFunc)();
+
+ class Q_SERVICEFW_EXPORT Entry {
+ public:
+ Entry();
+ Entry(const Entry &);
+ Entry &operator=(const Entry &);
+
+ ~Entry();
+
+ bool operator==(const Entry &) const;
+ bool operator!=(const Entry &) const;
+
+ bool isValid() const;
+
+ QString interfaceName() const;
+ QString serviceName() const;
+ QString version() const;
+
+ void setInstantiationType(QRemoteServiceRegister::InstanceType type);
+ QRemoteServiceRegister::InstanceType instantiationType() const;
+
+ private:
+ QExplicitlySharedDataPointer<QRemoteServiceRegisterEntryPrivate> d;
+
+ const QMetaObject* metaObject() const;
+
+ friend class QRemoteServiceRegister;
+ friend class InstanceManager;
+ friend class QServiceManager;
+#ifndef QT_NO_DATASTREAM
+ friend Q_SERVICEFW_EXPORT QDataStream &operator<<(QDataStream &, const QRemoteServiceRegister::Entry &);
+ friend Q_SERVICEFW_EXPORT QDataStream &operator>>(QDataStream &, QRemoteServiceRegister::Entry &);
+#endif
+ };
+
+ QRemoteServiceRegister(QObject* parent = 0);
+ ~QRemoteServiceRegister();
+
+ template <typename T>
+ Entry createEntry(const QString& serviceName,
+ const QString& interfaceName, const QString& version);
+
+ void publishEntries(const QString& ident );
+
+ bool quitOnLastInstanceClosed() const;
+ void setQuitOnLastInstanceClosed(const bool quit);
+
+ typedef bool (*SecurityFilter)(const void *message);
+ SecurityFilter setSecurityFilter(SecurityFilter filter);
+
+Q_SIGNALS:
+ void allInstancesClosed();
+ void instanceClosed(const QRemoteServiceRegister::Entry& entry);
+
+private:
+
+ Entry createEntry(const QString& serviceName,
+ const QString& interfaceName, const QString& version,
+ CreateServiceFunc cptr, const QMetaObject* meta);
+
+ QRemoteServiceRegisterPrivate* d;
+};
+
+struct QRemoteServiceRegisterCredentials {
+ int fd;
+ int pid;
+ int uid;
+ int gid;
+};
+
+inline uint qHash(const QRemoteServiceRegister::Entry& e) {
+ //Only consider version, iface and service name -> needs to sync with operator==
+ return ( qHash(e.serviceName()) + qHash(e.interfaceName()) + qHash(e.version()) );
+}
+
+#ifndef QT_NO_DATASTREAM
+QDataStream& operator>>(QDataStream& s, QRemoteServiceRegister::Entry& entry);
+QDataStream& operator<<(QDataStream& s, const QRemoteServiceRegister::Entry& entry);
+#endif
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QRemoteServiceRegister::Entry& entry);
+#endif
+
+template <typename T>
+QObject* qServiceTypeConstructHelper()
+{
+ return new T;
+}
+
+template <typename T>
+QRemoteServiceRegister::Entry QRemoteServiceRegister::createEntry(const QString& serviceName,
+ const QString& interfaceName, const QString& version)
+{
+
+ QRemoteServiceRegister::CreateServiceFunc cptr = qServiceTypeConstructHelper<T>;
+ return createEntry(serviceName, interfaceName, version, cptr, &T::staticMetaObject);
+}
+
+
+QTM_END_NAMESPACE
+#endif //QREMOTESERVICEREGISTER_H
diff --git a/src/serviceframework/qservice.h b/src/serviceframework/qservice.h
new file mode 100644
index 00000000..e7d5fdf3
--- /dev/null
+++ b/src/serviceframework/qservice.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef Q_SERVICE_H
+#define Q_SERVICE_H
+
+#include "qserviceframeworkglobal.h"
+
+QT_BEGIN_HEADER
+
+QTM_BEGIN_NAMESPACE
+
+//QTM_SYNC_HEADER_EXPORT QService
+namespace QService
+{
+ enum Scope {
+ UserScope = 0,
+ SystemScope
+ };
+
+ enum UnrecoverableIPCError {
+ ErrorUnknown = 0,
+ ErrorServiceNoLongerAvailable,
+ ErrorOutofMemory,
+ ErrorPermissionDenied,
+ ErrorInvalidArguments
+ };
+
+ enum Type {
+ Plugin = 0,
+ InterProcess
+ };
+}
+
+QTM_END_NAMESPACE
+
+QT_END_HEADER
+#endif //Q_SERVICE_H
diff --git a/src/serviceframework/qservice.qdoc b/src/serviceframework/qservice.qdoc
new file mode 100644
index 00000000..d1d8ef6c
--- /dev/null
+++ b/src/serviceframework/qservice.qdoc
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+/*!
+ \namespace QService
+ \ingroup servicefw
+ \inmodule QtServiceFramework
+
+ \brief The QService namespace contains miscellaneous identifiers used throughout the
+ Qt Service framework library.
+*/
+
+/*!
+ \enum QService::Scope
+ Defines the scope to be used when accessing services. Note that Symbian
+ does not distinguish scopes and therefore UserScope and SystemScope may
+ be used interchangeably.
+
+ \value UserScope When adding and removing services, uses a storage location
+ specific to the current user.
+ When searching for services and interface implementations, first searches in the
+ user-specific location; if the service or interface implementation
+ is not found, searches in the system-wide storage location (if the user has
+ sufficient permissions to do so).
+
+ \value SystemScope When adding and removing services, use a system-wide
+ storage location accessible to all users. When searching
+ for services and interface implementations, search only in the system-wide
+ storage location.
+*/
+
+/*!
+ \enum QService::UnrecoverableIPCError
+ Defines the unrecoverable IPC error of the service
+
+ \value ErrorUnknown An unknown IPC error.
+ \value ErrorServiceNoLongerAvailable Indicates that the service is no longer available.
+ \value ErrorOutofMemory Indicates that the service is out of memoruy.
+ \value ErrorPermissionDenied Indicates that the permission of this service is denied.
+ \value ErrorInvalidArguments User uses invalid argument for this service.
+*/
+
+/*!
+ \enum QService::Type
+ Defines the type of the service
+
+ \value Plugin This denotes that the service is plug-in based.
+ \value InterProcess This denotes that the service is deployed using IPC mechanisms
+ available on the current platform, such as DBus or local sockets.
+*/
diff --git a/src/serviceframework/qservicecontext.cpp b/src/serviceframework/qservicecontext.cpp
new file mode 100644
index 00000000..cfef3652
--- /dev/null
+++ b/src/serviceframework/qservicecontext.cpp
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qservicecontext.h"
+
+QTM_BEGIN_NAMESPACE
+
+#define CLIENT_DATA_INDEX 0
+
+class ServiceContextClientData : public QObjectUserData
+{
+public:
+ virtual ~ServiceContextClientData() {}
+
+ QHash<QString, QVariant> clientData;
+};
+
+
+/*!
+ \class QServiceContext
+ \inmodule QtServiceFramework
+ \ingroup servicefw
+ \brief The QServiceContext class provides context information to
+ services.
+ \since 1.0
+
+ A service context is created by clients and passed on to the service.
+ It enables the opportunity to pass additional context information
+ and errors between services, clients and the service framework.
+
+ Clients must implement this abstract class to receive context information.
+
+ \sa QServiceManager
+
+*/
+
+/*!
+ \enum QServiceContext::ContextType
+
+ This enum describes the type of context information.
+
+ \value DisplayContext The service provides user visible display
+ text such as an error message.
+ \value ScriptContext The service provides a script which may
+ be executed by the client.
+ \value UserDefined The first context type that can be used for service
+ specific context information.
+*/
+
+/*!
+ \fn void QServiceContext::notify(ContextType type, const QVariant& data) = 0
+
+ Services may call this function to notify the service client about service related
+ context information of the given \a type. The contextual information is stored in \a data.
+ \since 1.0
+*/
+
+
+/*!
+ Constructs a service context with the given \a parent.
+*/
+QServiceContext::QServiceContext(QObject* parent)
+ : QObject(parent)
+{
+#ifndef QT_NO_USERDATA
+ //Ideally we would use a new data member to store the client information.
+ //However since a d-pointer was forgotten when designing QServiceContext
+ //we need to fall back to QObject user data.
+ ServiceContextClientData* data = new ServiceContextClientData();
+ setUserData(CLIENT_DATA_INDEX, data);
+#endif
+}
+
+/*!
+ Destroys the service context object.
+*/
+QServiceContext::~QServiceContext()
+{
+ //ServiceContextUserData deleted by QObject
+}
+
+/*!
+ \property QServiceContext::clientId
+ \brief the id of the client using the service.
+
+ By default, this value is empty but you can change this by calling
+ setClientId().
+ \since 1.0
+*/
+QString QServiceContext::clientId() const
+{
+ return m_id;
+}
+
+/*!
+ Sets the \a id of the client using the service.
+ \since 1.0
+*/
+void QServiceContext::setClientId(const QString& id)
+{
+ m_id = id;
+}
+
+/*!
+ \property QServiceContext::clientName
+ \brief the name of the client using the service.
+
+ By default, this value is empty but you can change this by calling
+ setClientName(). This string is translated and can be shown to the user.
+ \since 1.0
+*/
+QString QServiceContext::clientName() const
+{
+ return m_displayName;
+}
+
+void QServiceContext::setClientName(const QString& name)
+{
+ m_displayName = name;
+}
+
+/*!
+ Returns the client data associated to \a key.
+
+ \sa setClientData(), resetClientData()
+ \since 1.1
+*/
+QVariant QServiceContext::clientData(const QString& key) const
+{
+#ifndef QT_NO_USERDATA
+ ServiceContextClientData* data =
+ static_cast<ServiceContextClientData*>(userData(CLIENT_DATA_INDEX));
+ return data->clientData.value(key);
+#else
+ return QVariant();
+#endif
+}
+
+/*!
+ Attaches arbitrary data \a value to the context object. The value
+ can be retrieved via \a key.
+
+ \sa clientData(), resetClientData()
+ \since 1.1
+*/
+void QServiceContext::setClientData(const QString& key, const QVariant& value)
+{
+#ifndef QT_NO_USERDATA
+ ServiceContextClientData* data =
+ static_cast<ServiceContextClientData*>(userData(CLIENT_DATA_INDEX));
+ data->clientData[key] = value;
+#endif
+}
+
+/*!
+ Deletes all client data associated to the service context.
+
+ \sa clientData(), setClientData()
+ \since 1.1
+*/
+void QServiceContext::resetClientData()
+{
+#ifndef QT_NO_USERDATA
+ ServiceContextClientData* data =
+ static_cast<ServiceContextClientData*>(userData(CLIENT_DATA_INDEX));
+ data->clientData.clear();
+#endif
+}
+
+#include "moc_qservicecontext.cpp"
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/qservicecontext.h b/src/serviceframework/qservicecontext.h
new file mode 100644
index 00000000..8271317b
--- /dev/null
+++ b/src/serviceframework/qservicecontext.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERVICECONTEXT_H
+#define QSERVICECONTEXT_H
+
+#include "qserviceframeworkglobal.h"
+#include <QObject>
+#include <QVariant>
+#include <QString>
+
+
+QT_BEGIN_HEADER
+
+QTM_BEGIN_NAMESPACE
+
+class Q_SERVICEFW_EXPORT QServiceContext : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString clientId READ clientId WRITE setClientId)
+ Q_PROPERTY(QString clientName READ clientName WRITE setClientName)
+public:
+ enum ContextType {
+ DisplayContext = 0,
+ ScriptContext,
+ UserDefined = 100
+ };
+
+ QServiceContext(QObject* parent = 0);
+ virtual ~QServiceContext();
+
+ virtual void notify( ContextType type, const QVariant& variant) = 0;
+
+
+ QString clientId() const;
+ void setClientId(const QString& clientId);
+
+ QString clientName() const;
+ void setClientName(const QString& name);
+
+ QVariant clientData(const QString& key) const;
+ void setClientData(const QString& key, const QVariant& value);
+ void resetClientData();
+
+private:
+ QString m_id;
+ QString m_displayName;
+
+};
+
+QTM_END_NAMESPACE
+
+QT_END_HEADER
+#endif //QSERVICECONTEXT_H
+
diff --git a/src/serviceframework/qservicefilter.cpp b/src/serviceframework/qservicefilter.cpp
new file mode 100644
index 00000000..84141cde
--- /dev/null
+++ b/src/serviceframework/qservicefilter.cpp
@@ -0,0 +1,540 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QRegExp>
+#include <QStringList>
+#include <QDebug>
+#ifndef QT_NO_DATASTREAM
+#include <qdatastream.h>
+#endif
+
+#include "qservicefilter.h"
+
+QTM_BEGIN_NAMESPACE
+
+class QServiceFilterPrivate
+{
+public:
+ QString interface;
+ QString service;
+ int majorVersion;
+ int minorVersion;
+ QServiceFilter::VersionMatchRule matchingRule;
+ QHash<QString,QString> customAttributes;
+ QStringList capabilities;
+ QServiceFilter::CapabilityMatchRule capMatchingRule;
+};
+
+
+/*!
+ \class QServiceFilter
+
+ \ingroup servicefw
+ \inmodule QtServiceFramework
+ \brief The QServiceFilter class defines criteria for defining a sub-set of
+ all available services.
+ \since 1.0
+
+ A QServiceFilter can be used to constrain the number of services when searching
+ for services. Only those services that match all filter criteria are returned
+ by \l QServiceManager::findInterfaces().
+
+
+ \sa QServiceInterfaceDescriptor, QServiceManager
+*/
+
+/*!
+ \enum QServiceFilter::VersionMatchRule
+
+ This enum describes how interface version matching is performed.
+
+ \value ExactVersionMatch The filter matches any interface implementation that implements
+ the exact version provided.
+ \value MinimumVersionMatch The filter matches any interface implementation that implements
+ either the given major/minor version or any subsequent version.
+*/
+
+/*!
+ \enum QServiceFilter::CapabilityMatchRule
+
+ This enum describes the capability/permission matching rules. Some platforms restrict what services clients
+ can access using "capabilities" or permissions. Services with more capabilities require
+ more privileged clients. Platforms without capabilities may ignore this type of matching
+ rule as the default behavior is to ignore any capability restrictions.
+
+ This is a brief example. Assuming that the system knows the services S1 - S6 which require capabilities as stated below:
+ \table
+ \header \o Service \o Required capabilities
+ \row \o S1 \o \{\}
+ \row \o S2 \o \{A\}
+ \row \o S3 \o \{A,B\}
+ \row \o S4 \o \{A,B,C,D\}
+ \row \o S5 \o \{A,D\}
+ \row \o S6 \o \{F\}
+ \endtable
+
+ The matching rules would apply as follows:
+
+ \table
+ \header \o Matching rule \o Filter's capabilities \o Matching services
+ \row \o MatchLoadable \o \{\} \o S1
+ \row \o MatchLoadable \o \{A\} \o S1, S2
+ \row \o MatchLoadable \o \{A,B,C\} \o S1, S2, S3
+ \row \o MatchMinimum \o \{\} \o S1, S2, S3, S4, S5, S6
+ \row \o MatchMinimum \o \{A\} \o S2, S3, S4, S5
+ \row \o MatchMinimum \o \{A,B,C\} \o S4
+ \endtable
+
+ \value MatchMinimum The filter matches any service that requires at least the given
+ filter capabilities. This may mean that the returned services
+ may require more capabilities than the specified ones.
+ Such a search is equivalent to a wildcard match if the passed filter's capability list is empty. In mathematical set notation
+ this rule is equivalent to Cap\sub{(Filter)} \\ Cap\sub{(Service)} = {}. This is the default matching rule.
+ \value MatchLoadable The filter matches any service that could be loaded by the client.
+ Using this matching rule guarantees that the returned services do not
+ require more capabilites than specified by this rule. It includes services
+ with no capability requirements. If this rule
+ is provided alongside an empty capability search list the returned
+ services do not require any capabilities and thus can be accessed
+ by any client. The equivalent set notation is Cap\sub{(Service)} \\ Cap\sub{(Filter)} = {}.
+*/
+
+/*!
+ Creates a new filter object that matches all service implementations.
+*/
+QServiceFilter::QServiceFilter()
+{
+ d = new QServiceFilterPrivate();
+ d->majorVersion = -1;
+ d->minorVersion = -1;
+ d->matchingRule = QServiceFilter::MinimumVersionMatch;
+ d->capMatchingRule = QServiceFilter::MatchMinimum;
+}
+
+/*!
+ Creates a copy of QServiceFilter object contained in \a other.
+*/
+QServiceFilter::QServiceFilter(const QServiceFilter& other)
+{
+ d = new QServiceFilterPrivate();
+ (*this) = other;
+}
+
+/*!
+ \fn QServiceFilter::QServiceFilter(const QString& interfaceName, const QString& version, QServiceFilter::VersionMatchRule rule)
+
+ Creates a new filter object that matches all service
+ implementations implementing \a interfaceName that match the specified
+ \a version using the given \a rule.
+ \since 1.0
+*/
+QServiceFilter::QServiceFilter(const QString& interfaceName, const QString& version, QServiceFilter::VersionMatchRule rule)
+{
+ d = new QServiceFilterPrivate();
+ d->majorVersion = -1;
+ d->minorVersion = -1;
+ d->matchingRule = QServiceFilter::MinimumVersionMatch;
+ d->capMatchingRule = QServiceFilter::MatchMinimum;
+ setInterface(interfaceName, version, rule);
+}
+
+/*!
+ Destroys this instance of QServiceFilter.
+*/
+QServiceFilter::~QServiceFilter()
+{
+ delete d;
+}
+
+/*!
+ \fn QServiceFilter& QServiceFilter::operator=(const QServiceFilter& other)
+
+ Copies the content of the QServiceFilter object contained in
+ \a other into this one.
+ \since 1.0
+*/
+QServiceFilter& QServiceFilter::operator=(const QServiceFilter& other)
+{
+ d->interface = other.d->interface;
+ d->service = other.d->service;
+ d->majorVersion = other.d->majorVersion;
+ d->minorVersion = other.d->minorVersion;
+ d->matchingRule = other.d->matchingRule;
+ d->customAttributes = other.d->customAttributes;
+ d->capabilities = other.d->capabilities;
+ d->capMatchingRule = other.d->capMatchingRule;
+
+ return *this;
+}
+
+/*!
+ \fn void QServiceFilter::setServiceName(const QString& serviceName)
+
+ The filter only matches implementations which are provided by the service
+ specified by \a serviceName.
+
+ If the \a serviceName is empty the filter matches any service.
+ \since 1.0
+*/
+void QServiceFilter::setServiceName(const QString& serviceName)
+{
+ d->service = serviceName;
+}
+
+/*!
+ \fn void QServiceFilter::setInterface(const QString &interfaceName, const QString& version, QServiceFilter::VersionMatchRule rule)
+
+ Sets the filter to match any interface implementation that implements
+ \a interfaceName with version \a version. The version is matched
+ according to the given \a rule. If \a version is not set, the filter matches any version of the
+ interface implementation.
+
+ This method does nothing if \a version is not a valid version string or
+ if \a interfaceName is empty.
+
+ A valid version string has the format x.y whereby x and y are positive integer
+ numbers.
+ \since 1.0
+*/
+void QServiceFilter::setInterface(const QString &interfaceName, const QString& version, QServiceFilter::VersionMatchRule rule)
+{
+ //unset interface name
+ if (interfaceName.isEmpty() && version.isEmpty())
+ {
+ d->interface = interfaceName;
+ d->majorVersion = d->minorVersion = -1;
+ d->matchingRule = rule;
+ return;
+ }
+
+ if (interfaceName.isEmpty()) {
+ qWarning() << "Empty interface name. Ignoring filter details";
+ return;
+ }
+
+ if (version.isEmpty()) {
+ d->majorVersion = d->minorVersion = -1;
+ d->matchingRule = rule;
+ d->interface = interfaceName;
+ return;
+ }
+
+ // Match x.y as version format.
+ // This differs from regex in servicemetadata in that 0.x versions are
+ // accepted for the search filter.
+ QRegExp rx(QLatin1String("^(0+|[1-9][0-9]*)\\.(0+|[1-9][0-9]*)$"));
+ int pos = rx.indexIn(version);
+ QStringList list = rx.capturedTexts();
+ bool success = false;
+ int temp_major = -1;
+ int temp_minor = -1;
+ if (pos == 0 && list.count() == 3
+ && rx.matchedLength() == version.length() )
+ {
+ temp_major = list[1].toInt(&success);
+ if ( success ) {
+ temp_minor = list[2].toInt(&success);
+ }
+ }
+
+ if (success) {
+ d->majorVersion = temp_major;
+ d->minorVersion = temp_minor;
+ d->interface = interfaceName;
+ d->matchingRule = rule;
+ } else {
+ qWarning() << "Invalid version tag" << version << ". Ignoring filter details.";
+ }
+}
+
+/*!
+ \fn QString QServiceFilter::serviceName() const
+
+ Returns the service name for this filter.
+
+ \sa setServiceName()
+ \since 1.0
+*/
+QString QServiceFilter::serviceName() const
+{
+ return d->service;
+}
+
+/*!
+ \fn QString QServiceFilter::interfaceName() const
+
+ Returns the interface name for this filter.
+
+ \sa setInterface()
+ \since 1.0
+*/
+QString QServiceFilter::interfaceName() const
+{
+ return d->interface;
+}
+
+/*!
+ \fn int QServiceFilter::majorVersion() const
+
+ Returns the major interface version for this filter.
+
+ \sa setInterface()
+ \since 1.0
+*/
+int QServiceFilter::majorVersion() const
+{
+ return d->majorVersion;
+}
+
+/*!
+ \fn int QServiceFilter::minorVersion() const
+
+ Returns the minor interface version for this filter.
+
+ \sa setInterface()
+ \since 1.0
+*/
+int QServiceFilter::minorVersion() const
+{
+ return d->minorVersion;
+}
+
+/*!
+ \fn void QServiceFilter::setCustomAttribute(const QString& key, const QString& value)
+
+ The filter only matches implementations which have the custom attribute
+ \a key with the given \a value. Such constraints are specified via the
+ \i{<customproperty>} tag within the service xml.
+
+ \sa customAttribute(), clearCustomAttribute()
+ \since 1.0
+*/
+void QServiceFilter::setCustomAttribute(const QString& key, const QString& value)
+{
+ d->customAttributes.insert(key, value);
+}
+
+/*!
+ \fn QString QServiceFilter::customAttribute(const QString& key) const
+
+ Returns the value for the custom attribute \a key; otherwise
+ returns a null string.
+
+ \sa setCustomAttribute(), clearCustomAttribute()
+ \since 1.0
+*/
+QString QServiceFilter::customAttribute(const QString& key) const
+{
+ return d->customAttributes.value(key);
+}
+
+/*!
+ \fn void QServiceFilter::clearCustomAttribute(const QString &key)
+
+ Clears the custom attribute \a key from the filter's set of constraints.
+ If \a key is empty all custom attributes are cleared.
+
+ \sa setCustomAttribute()
+ \since 1.0
+*/
+void QServiceFilter::clearCustomAttribute(const QString &key)
+{
+ if (key.isEmpty())
+ d->customAttributes.clear();
+ else
+ d->customAttributes.remove(key);
+}
+
+/*!
+ \fn QServiceFilter::VersionMatchRule QServiceFilter::versionMatchRule() const
+
+ Returns the version match rule for this filter.
+
+ \sa setInterface()
+ \since 1.0
+*/
+QServiceFilter::VersionMatchRule QServiceFilter::versionMatchRule() const
+{
+ return d->matchingRule;
+}
+
+/*!
+ \fn QList<QString> QServiceFilter::customAttributes() const
+
+ Returns the list of custom keys which have been added to the filter.
+ \since 1.0
+*/
+QStringList QServiceFilter::customAttributes() const
+{
+ return d->customAttributes.keys();
+}
+
+/*!
+ \fn void QServiceFilter::setCapabilities(QServiceFilter::CapabilityMatchRule rule, const QStringList& capabilities )
+
+ Sets the list of \a capabilities which are used to constrain
+ searches for services. The capabilities are matched according
+ to the given \a rule.
+
+ \sa capabilities(), QAbstractSecuritySession
+ \since 1.0
+*/
+void QServiceFilter::setCapabilities(QServiceFilter::CapabilityMatchRule rule, const QStringList& capabilities )
+{
+ d->capMatchingRule = rule;
+ d->capabilities = capabilities;
+}
+
+/*!
+ \fn QStringList QServiceFilter::capabilities() const
+
+ Returns the list of capabilities which are used to limit services searches.
+
+ The filter matches any services that requires the given or less
+ capabilities and thus enabling clients to query for services
+ for which they have the required capabilties.
+
+ \sa setCapabilities(), capabilityMatchRule(), QAbstractSecuritySession
+ \since 1.0
+*/
+QStringList QServiceFilter::capabilities() const
+{
+ return d->capabilities;
+}
+
+/*!
+ Returns the capability matching rule for this filter.
+
+ \sa setCapabilities(), capabilities()
+ \since 1.0
+*/
+QServiceFilter::CapabilityMatchRule QServiceFilter::capabilityMatchRule() const
+{
+ return d->capMatchingRule;
+}
+
+#ifndef QT_NO_DATASTREAM
+/*!
+ \fn QDataStream &operator<<(QDataStream &out, const QServiceFilter &sf)
+ \relates QServiceFilter
+
+ Writes service filter \a sf to the stream \a out and returns a reference
+ to the stream.
+ \since 1.0
+*/
+
+QDataStream &operator<<(QDataStream &out, const QServiceFilter &sf)
+{
+ const quint32 magicNumber = 0x78AFAFA;
+ const qint32 mj = sf.d->majorVersion;
+ const qint32 mn = sf.d->minorVersion;
+ const qint8 versionrule = (qint32) sf.d->matchingRule;
+ const qint8 caprule = (qint8) sf.d->capMatchingRule;
+ const quint16 majorVersion = 1;
+ const quint16 minorVersion = 0;
+
+ out << magicNumber
+ << majorVersion
+ << minorVersion
+ << sf.d->interface
+ << sf.d->service
+ << mj
+ << mn
+ << versionrule
+ << sf.d->customAttributes
+ << caprule
+ << sf.d->capabilities;
+ return out;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &in, QServiceFilter &sf)
+ \relates QServiceFilter
+
+ Reads a service filter into \a sf from the stream \a in and returns a
+ reference to the stream.
+ \since 1.0
+*/
+QDataStream &operator>>(QDataStream &in, QServiceFilter &sf)
+{
+ const quint32 magicNumber = 0x78AFAFA;
+ qint32 mj, mn;
+ qint8 versionrule, caprule;
+
+ quint32 storedMagicNumber;
+ in >> storedMagicNumber;
+ if (storedMagicNumber != magicNumber) {
+ qWarning() << "Datastream doesn't provide serialized QServiceFilter";
+ return in;
+ }
+
+ const quint16 currentMajorVersion = 1;
+ quint16 majorVersion = 0;
+ quint16 minorVersion = 0;
+
+ in >> majorVersion >> minorVersion;
+ if (majorVersion != currentMajorVersion) {
+ qWarning() << "Unknown serialization format for QServiceFilter.";
+ return in;
+ }
+ //Allow all minor versions.
+
+ in >> sf.d->interface
+ >> sf.d->service
+ >> mj
+ >> mn
+ >> versionrule
+ >> sf.d->customAttributes
+ >> caprule
+ >> sf.d->capabilities;
+
+ sf.d->majorVersion = mj;
+ sf.d->minorVersion = mn;
+ sf.d->matchingRule = (QServiceFilter::VersionMatchRule) versionrule;
+ sf.d->capMatchingRule = (QServiceFilter::CapabilityMatchRule) caprule;
+
+ return in;
+}
+#endif //QT_NO_DATASTREAM
+
+
+QTM_END_NAMESPACE
+
diff --git a/src/serviceframework/qservicefilter.h b/src/serviceframework/qservicefilter.h
new file mode 100644
index 00000000..9a432ecb
--- /dev/null
+++ b/src/serviceframework/qservicefilter.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERVICEFILTER_H
+#define QSERVICEFILTER_H
+
+#include "qserviceframeworkglobal.h"
+#include <QStringList>
+
+QT_BEGIN_NAMESPACE
+class QDataStream;
+QT_END_NAMESPACE
+
+QT_BEGIN_HEADER
+
+QTM_BEGIN_NAMESPACE
+
+#ifdef QT_SFW_SERVICEDATABASE_GENERATE
+#undef Q_SERVICEFW_EXPORT
+#define Q_SERVICEFW_EXPORT
+#endif
+
+class QServiceFilterPrivate;
+class Q_SERVICEFW_EXPORT QServiceFilter
+{
+public:
+ enum VersionMatchRule {
+ ExactVersionMatch = 0,
+ MinimumVersionMatch
+ };
+
+ enum CapabilityMatchRule {
+ MatchMinimum = 0,
+ MatchLoadable
+ };
+
+ QServiceFilter();
+ ~QServiceFilter();
+ QServiceFilter(const QServiceFilter& other);
+ explicit QServiceFilter(const QString& interfaceName,
+ const QString& version = QString(),
+ QServiceFilter::VersionMatchRule rule = QServiceFilter::MinimumVersionMatch);
+
+ QServiceFilter& operator=(const QServiceFilter& other);
+
+ void setInterface(const QString& interfaceName, const QString& version = QString(),
+ QServiceFilter::VersionMatchRule rule = QServiceFilter::MinimumVersionMatch);
+ void setServiceName(const QString& serviceName);
+
+
+ QString serviceName() const;
+ QString interfaceName() const;
+ int majorVersion() const;
+ int minorVersion() const;
+ VersionMatchRule versionMatchRule() const;
+
+ QStringList customAttributes() const;
+ QString customAttribute(const QString& which) const;
+ void setCustomAttribute(const QString& key, const QString& value);
+ void clearCustomAttribute(const QString &key = QString());
+
+ void setCapabilities(QServiceFilter::CapabilityMatchRule, const QStringList& capabilities = QStringList() );
+ QStringList capabilities() const;
+ CapabilityMatchRule capabilityMatchRule() const;
+
+private:
+ QServiceFilterPrivate *d;
+ friend class QServiceManager;
+ //friend class ServiceDatabase;
+#ifndef QT_NO_DATASTREAM
+ friend Q_SERVICEFW_EXPORT QDataStream &operator<<(QDataStream &, const QServiceFilter &);
+ friend Q_SERVICEFW_EXPORT QDataStream &operator>>(QDataStream &, QServiceFilter &);
+#endif
+};
+
+#ifndef QT_NO_DATASTREAM
+Q_SERVICEFW_EXPORT QDataStream &operator<<(QDataStream &, const QServiceFilter &);
+Q_SERVICEFW_EXPORT QDataStream &operator>>(QDataStream &, QServiceFilter &);
+#endif
+
+QTM_END_NAMESPACE
+
+QT_END_HEADER
+#endif //QSERVICEFILTER_H
diff --git a/src/serviceframework/qserviceframeworkglobal.h b/src/serviceframework/qserviceframeworkglobal.h
new file mode 100644
index 00000000..2a9382d3
--- /dev/null
+++ b/src/serviceframework/qserviceframeworkglobal.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QSERVICEFRAMEWORK_H
+#define QSERVICEFRAMEWORK_H
+
+#include <QtCore/qglobal.h>
+
+// The namespace is hardcoded as moc has issues resolving
+// macros which would be a prerequisite for a dynmamic namespace
+//#define QTM_NAMESPACE QtMobility
+//#define QTM_NAMESPACE
+
+#if defined(Q_OS_WIN)
+# if defined(QT_NODLL)
+# undef QT_MAKEDLL
+# undef QT_DLL
+# elif defined(QT_MAKEDLL)
+# if defined(QT_DLL)
+# undef QT_DLL
+# endif
+# if defined(QT_BUILD_SFW_LIB)
+# define Q_SERVICEFW_EXPORT Q_DECL_EXPORT
+# else
+# define Q_SERVICEFW_EXPORT Q_DECL_IMPORT
+# endif
+# elif defined(QT_DLL)
+# define Q_SERVICEFW_EXPORT Q_DECL_EXPORT
+# endif
+#endif
+
+#if !defined(Q_SERVICEFW_EXPORT)
+# if defined(QT_SHARED)
+# define Q_SERVICEFW_EXPORT Q_DECL_EXPORT
+# else
+# define Q_SERVICEFW_EXPORT
+# endif
+#endif
+
+#ifdef QTM_NAMESPACE
+# define QTM_PREPEND_NAMESPACE(name) ::QTM_NAMESPACE::name
+# define QTM_BEGIN_NAMESPACE namespace QTM_NAMESPACE {
+# define QTM_END_NAMESPACE }
+# define QTM_USE_NAMESPACE using namespace QTM_NAMESPACE;
+#else
+# define QTM_PREPEND_NAMESPACE(name) ::name
+# define QTM_BEGIN_NAMESPACE
+# define QTM_END_NAMESPACE
+# define QTM_USE_NAMESPACE
+#endif
+
+//in case Qt is in namespace
+QT_USE_NAMESPACE
+
+#endif // QSERVICEFRAMEWORK_H
+
diff --git a/src/serviceframework/qserviceinterfacedescriptor.cpp b/src/serviceframework/qserviceinterfacedescriptor.cpp
new file mode 100644
index 00000000..377c57aa
--- /dev/null
+++ b/src/serviceframework/qserviceinterfacedescriptor.cpp
@@ -0,0 +1,418 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qserviceinterfacedescriptor_p.h"
+#ifndef QT_NO_DATASTREAM
+#include <qdatastream.h>
+#endif
+
+#include <QDebug>
+#include <QStringList>
+
+QTM_BEGIN_NAMESPACE
+
+/*!
+ \class QServiceInterfaceDescriptor
+ \ingroup servicefw
+ \inmodule QtServiceFramework
+ \brief The QServiceInterfaceDescriptor class identifies a service implementation.
+ \since 1.0
+
+ A service can implement multiple interfaces and each interface can have multiple implementations.
+ The QServiceInterfaceDescriptor class enscapsulates this information, as illustrated
+ by the diagram below.
+
+ \image qserviceinterfacedescriptor.png Service-Interface-Implementation
+
+ The major version tag indicates the interface version and the minor version tag identifies the implementation
+ version. Subsequent versions of the same interface must be binary compatible to previous versions
+ of the same interface.
+
+ In the above example service A and B implement the interface \i com.nokia.qt.x.
+ In fact Service A provides two different implementations for the very same interface.
+ This is indicated by the changed minor version number. Although Service B is
+ using the same interface it's implementation actually utilizes the second version of
+ the interface \i com.nokia.qt.x. Binary compatibility guarantees that clients
+ who know version 1 can utilize version 2. If an existing interface has to be changed
+ in a non-compatible way a new interface (name) is required.
+
+ \section1 Namespaces
+
+ A QServiceInterfaceDescriptor (the quadruble of service name,
+ interface name, interface version and implementation version) uniquely
+ identifies a service implementation on a device. Interface names follow
+ the java namespace convention.
+
+ The namespace \i com.nokia.qt.* is reserved for future Qt development.
+
+ \sa QServiceFilter, QServiceManager
+*/
+
+/*!
+ \enum QServiceInterfaceDescriptor::Attribute
+
+ This enum describes the possible attribute types which can be attached
+ to a QServiceInterfaceDescriptor.
+
+ \value Capabilities The capabilities attribute is a QStringList and
+ describes the capabilities that a service client
+ would require to use the service if capability
+ checks are enforced.
+ \value Location This attribute points to either the location
+ where the plug-in providing this service is stored or
+ where the name of the service IPC path is found.
+ If the service is plug-in based the location is the
+ name and/or path of the plugin. If the service is
+ IPC based the location is the name of the socket address.
+ \value ServiceDescription This attribute provides a general description for
+ the service.
+ \value InterfaceDescription This attribute provides a description for the interface
+ implementation.
+ \value ServiceType This attribute specifies the QService::Type that the
+ service is being provided.
+*/
+
+/*!
+ Creates a new QServiceInterfaceDescriptor.
+*/
+QServiceInterfaceDescriptor::QServiceInterfaceDescriptor()
+ : d(0)
+{
+}
+
+/*!
+ Destroys the QServiceInterfaceDescriptor object.
+*/
+QServiceInterfaceDescriptor::~QServiceInterfaceDescriptor()
+{
+ if (d)
+ delete d;
+}
+
+/*!
+ Creates a copy of QServiceInterfaceDescriptor contained in \a other.
+ \since 1.0
+*/
+QServiceInterfaceDescriptor::QServiceInterfaceDescriptor(const QServiceInterfaceDescriptor& other)
+ : d(0)
+{
+ (*this) = other; //use assignment operator
+}
+
+/*!
+ \fn QServiceInterfaceDescriptor& QServiceInterfaceDescriptor::operator=(const QServiceInterfaceDescriptor& other)
+
+ Copies the content of the QServiceInterfaceDescriptor object contained
+ in \a other into this one.
+ \since 1.0
+*/
+QServiceInterfaceDescriptor& QServiceInterfaceDescriptor::operator=(const QServiceInterfaceDescriptor& other)
+{
+ if ( !other.isValid() ) {
+ if (d)
+ delete d;
+ d = 0;
+ return *this;
+ }
+
+ if (!d)
+ d = new QServiceInterfaceDescriptorPrivate;
+
+ (*d) = *(other.d);
+ return *this;
+}
+
+/*!
+ \fn bool QServiceInterfaceDescriptor::operator==(const QServiceInterfaceDescriptor& other) const
+
+ Compares a QServiceInterfaceDescriptor to \a other. Returns true if they
+ are equal and false otherwise.
+ \since 1.0
+*/
+bool QServiceInterfaceDescriptor::operator==(const QServiceInterfaceDescriptor& other) const
+{
+ if (isValid() ^ other.isValid())
+ return false;
+
+ if (!d)
+ return true;
+
+ if ((*d) == *(other.d))
+ return true;
+ return false;
+}
+
+/*!
+ \fn bool QServiceInterfaceDescriptor::operator!=(const QServiceInterfaceDescriptor& other) const
+
+ Compares a QServiceInterfaceDescriptor to \a other. Returns true
+ if they are not equal and false otherwise.
+ \since 1.0
+*/
+
+/*!
+ \fn bool QServiceInterfaceDescriptor::isValid() const
+
+ Returns true if this descriptor is valid; otherwise returns false.
+ \since 1.0
+*/
+bool QServiceInterfaceDescriptor::isValid() const
+{
+ return d ? true : false;
+}
+
+/*!
+ \fn bool QServiceInterfaceDescriptor::scope() const
+
+ Returns true if this implementation is provided for all users on the system.
+
+ \sa QService::Scope
+ \since 1.0
+*/
+QService::Scope QServiceInterfaceDescriptor::scope() const
+{
+ return d ? d->scope : QService::UserScope;
+}
+
+/*!
+ \fn QString QServiceInterfaceDescriptor::serviceName() const
+
+ Returns the name of service that provides this implementation.
+ \since 1.0
+*/
+QString QServiceInterfaceDescriptor::serviceName() const
+{
+ return d ? d->serviceName : QString();
+}
+
+/*!
+ \fn QString QServiceInterfaceDescriptor::interfaceName() const
+
+ Returns the name of the interface that is implemented.
+ \since 1.0
+*/
+QString QServiceInterfaceDescriptor::interfaceName() const
+{
+ return d ? d->interfaceName : QString();
+}
+
+/*!
+ \fn int QServiceInterfaceDescriptor::majorVersion() const
+
+ Returns the version of the interface.
+
+ Subsequent versions of an interface are binary compatible
+ to previous versions of the same interface. If an interface
+ is broken it must use a new interface name.
+ \since 1.0
+*/
+int QServiceInterfaceDescriptor::majorVersion() const
+{
+ return d ? d->major : -1;
+}
+
+/*!
+ \fn int QServiceInterfaceDescriptor::minorVersion() const
+
+ Returns the version of the implementation.
+ \since 1.0
+*/
+int QServiceInterfaceDescriptor::minorVersion() const
+{
+ return d ? d->minor : -1;
+}
+
+/*!
+ \fn QVariant QServiceInterfaceDescriptor::attribute(QServiceInterfaceDescriptor::Attribute which) const
+
+ Returns the value for the attribute \a which; otherwise returns
+ an invalid QVariant.
+ \since 1.0
+*/
+QVariant QServiceInterfaceDescriptor::attribute(QServiceInterfaceDescriptor::Attribute which) const
+{
+ if (d)
+ return d->attributes.value(which);
+ return QVariant();
+}
+
+/*!
+ \fn QString QServiceInterfaceDescriptor::customAttribute(const QString& which) const
+
+ Returns the value for the custom attribute \a which; otherwise
+ returns a null string.
+ \since 1.0
+*/
+QString QServiceInterfaceDescriptor::customAttribute(const QString& which) const
+{
+ if (d)
+ return d->customAttributes[which];
+ return QString();
+}
+
+/*!
+ Returns a list of custom attributes attached to the service.
+ \since 1.0
+ */
+QStringList QServiceInterfaceDescriptor::customAttributes() const
+{
+ if (d)
+ return d->customAttributes.keys();
+ return QStringList();
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QServiceInterfaceDescriptor &desc)
+{
+ if (desc.isValid()) {
+ QString interface = QString(QLatin1String("%1 %2.%3")).arg(desc.interfaceName())
+ .arg(desc.majorVersion() < 0 ? '?' : desc.majorVersion())
+ .arg(desc.minorVersion() < 0 ? '?' : desc.minorVersion());
+ dbg.nospace() << "QServiceInterfaceDescriptor(";
+ dbg.nospace() << "service=" << desc.serviceName() << ", ";
+ dbg.nospace() << "interface=" << interface;
+ dbg.nospace() << ")";
+ } else {
+ dbg.nospace() << "QServiceInterfaceDescriptor(invalid)";
+ }
+ return dbg.space();
+}
+#endif
+
+#ifndef QT_NO_DATASTREAM
+
+QDataStream &operator<<(QDataStream &out, const QServiceInterfaceDescriptor::Attribute &k)
+{
+ out << qint8(k);
+ return out;
+}
+
+QDataStream &operator>>(QDataStream &in, QServiceInterfaceDescriptor::Attribute &k)
+{
+ quint8 key;
+ in >> key;
+ k = (QServiceInterfaceDescriptor::Attribute)key;
+ return in;
+}
+/*!
+ \fn QDataStream &operator<<(QDataStream &out, const QServiceInterfaceDescriptor &dc)
+ \relates QServiceInterfaceDescriptor
+
+ Writes service interface descriptor \a dc to the stream \a out and returns a reference
+ to the stream.
+ \since 1.0
+*/
+
+QDataStream &operator<<(QDataStream &out, const QServiceInterfaceDescriptor &dc)
+{
+ const quint32 magicNumber = 0x77AFAFA;
+ const quint16 majorVersion = 1;
+ const quint16 minorVersion = 0;
+ const qint8 valid = dc.isValid();
+ out << magicNumber << majorVersion << minorVersion;
+ out << valid;
+ if (valid) {
+ out << dc.d->serviceName;
+ out << dc.d->interfaceName;
+ out << dc.d->major;
+ out << dc.d->minor;
+ out << dc.d->attributes;
+ out << dc.d->customAttributes;
+ out << (qint8)dc.d->scope;
+ }
+ return out;
+}
+
+/*!
+ \fn QDataStream &operator>>(QDataStream &in, QServiceInterfaceDescriptor &dc)
+ \relates QServiceInterfaceDescriptor
+
+ Reads a service interface descriptor into \a dc from the stream \a in and returns a
+ reference to the stream.
+ \since 1.0
+*/
+QDataStream &operator>>(QDataStream &in, QServiceInterfaceDescriptor &dc)
+{
+ const quint32 magicNumber = 0x77AFAFA;
+ quint32 storedMagicNumber;
+ in >> storedMagicNumber;
+ if (storedMagicNumber != magicNumber) {
+ qWarning() << "Datastream doesn't provide searialized QServiceInterfaceDescriptor";
+ return in;
+ }
+
+ const quint16 currentMajorVersion = 1;
+ quint16 majorVersion = 0;
+ quint16 minorVersion = 0;
+
+ in >> majorVersion >> minorVersion;
+ if (majorVersion != currentMajorVersion) {
+ qWarning() << "Unknown serialization format for QServiceInterfaceDescriptor.";
+ return in;
+ }
+ //Allow all minor versions.
+
+ qint8 valid;
+ in >> valid;
+ if (valid) {
+ if (!dc.isValid())
+ dc.d = new QServiceInterfaceDescriptorPrivate;
+ in >> dc.d->serviceName;
+ in >> dc.d->interfaceName;
+ in >> dc.d->major;
+ in >> dc.d->minor;
+ in >> dc.d->attributes;
+ in >> dc.d->customAttributes;
+ in >> valid;
+ dc.d->scope = (QService::Scope) valid;
+ } else { //input stream contains invalid descriptor
+ //use assignment operator
+ dc = QServiceInterfaceDescriptor();
+ }
+
+ return in;
+}
+#endif //QT_NO_DATASTREAM
+
+
+
+QTM_END_NAMESPACE
+
diff --git a/src/serviceframework/qserviceinterfacedescriptor.h b/src/serviceframework/qserviceinterfacedescriptor.h
new file mode 100644
index 00000000..9d6614ce
--- /dev/null
+++ b/src/serviceframework/qserviceinterfacedescriptor.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERVICEINTERFACEDESCRIPTOR_H
+#define QSERVICEINTERFACEDESCRIPTOR_H
+
+#include "qserviceframeworkglobal.h"
+#include <QString>
+#include <QVariant>
+#include "qservice.h"
+
+QT_USE_NAMESPACE
+
+#ifdef SERVICE_XML_GENERATOR
+#undef Q_SERVICEFW_EXPORT
+#define Q_SERVICEFW_EXPORT
+#endif
+
+QT_BEGIN_NAMESPACE
+class QDebug;
+class QStringList;
+class QDataStream;
+QT_END_NAMESPACE
+
+QT_BEGIN_HEADER
+
+QTM_BEGIN_NAMESPACE
+
+class QServiceInterfaceDescriptorPrivate;
+class Q_SERVICEFW_EXPORT QServiceInterfaceDescriptor
+{
+public:
+ enum Attribute {
+ Capabilities = 0,
+ Location,
+ ServiceDescription,
+ InterfaceDescription,
+ ServiceType
+ };
+
+ QServiceInterfaceDescriptor();
+ QServiceInterfaceDescriptor(const QServiceInterfaceDescriptor& other);
+ ~QServiceInterfaceDescriptor();
+
+ QServiceInterfaceDescriptor& operator=(const QServiceInterfaceDescriptor& other);
+ bool operator==(const QServiceInterfaceDescriptor& other) const;
+ inline bool operator!=(const QServiceInterfaceDescriptor& other) const
+ { return !operator==(other); }
+
+ QString serviceName() const;
+ QString interfaceName() const;
+ int majorVersion() const;
+ int minorVersion() const;
+
+ bool isValid() const;
+
+ QService::Scope scope() const;
+
+ QVariant attribute(QServiceInterfaceDescriptor::Attribute which) const;
+ QString customAttribute(const QString& which) const;
+ QStringList customAttributes() const;
+
+private:
+ QServiceInterfaceDescriptorPrivate* d;
+
+ friend class QServiceInterfaceDescriptorPrivate;
+ friend class QServiceManager;
+ friend class ServiceDatabase;
+ friend class ServiceMetaData;
+ friend class DatabaseManager;
+#ifndef QT_NO_DATASTREAM
+ friend Q_SERVICEFW_EXPORT QDataStream &operator<<(QDataStream &, const QServiceInterfaceDescriptor &);
+ friend Q_SERVICEFW_EXPORT QDataStream &operator>>(QDataStream &, QServiceInterfaceDescriptor &);
+#endif
+};
+
+#ifndef QT_NO_DATASTREAM
+Q_SERVICEFW_EXPORT QDataStream &operator<<(QDataStream &, const QServiceInterfaceDescriptor &);
+Q_SERVICEFW_EXPORT QDataStream &operator>>(QDataStream &, QServiceInterfaceDescriptor &);
+#endif
+#ifndef QT_NO_DEBUG_STREAM
+Q_SERVICEFW_EXPORT QDebug operator<<(QDebug, const QServiceInterfaceDescriptor &);
+#endif
+
+
+QTM_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/serviceframework/qserviceinterfacedescriptor_p.h b/src/serviceframework/qserviceinterfacedescriptor_p.h
new file mode 100644
index 00000000..512572c6
--- /dev/null
+++ b/src/serviceframework/qserviceinterfacedescriptor_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERVICEINTERFACEDESCRIPTOR_P_H
+#define QSERVICEINTERFACEDESCRIPTOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qserviceinterfacedescriptor.h"
+
+#include <QString>
+#include <QHash>
+
+QTM_BEGIN_NAMESPACE
+
+#define SERVICE_INITIALIZED_ATTR "INITIALIZED"
+
+class QServiceInterfaceDescriptorPrivate
+{
+public:
+ QServiceInterfaceDescriptorPrivate()
+ {
+ major = -1;
+ minor = -1;
+ scope = QService::UserScope;
+ }
+
+ bool operator==(const QServiceInterfaceDescriptorPrivate& other) const
+ {
+ if (major == other.major
+ && minor == other.minor
+ && interfaceName == other.interfaceName
+ && serviceName == other.serviceName
+ && attributes == other.attributes
+ && customAttributes == other.customAttributes
+ && scope == other.scope)
+ return true;
+ return false;
+ }
+
+ QServiceInterfaceDescriptorPrivate& operator=(const QServiceInterfaceDescriptorPrivate& other)
+ {
+ serviceName = other.serviceName;
+ interfaceName = other.interfaceName;
+ minor = other.minor;
+ major = other.major;
+ attributes = other.attributes;
+ customAttributes = other.customAttributes;
+ scope = other.scope;
+
+ return *this;
+ }
+
+ static QServiceInterfaceDescriptorPrivate *getPrivate(QServiceInterfaceDescriptor *descriptor)
+ {
+ return descriptor->d;
+ }
+
+ static const QServiceInterfaceDescriptorPrivate *getPrivate(const QServiceInterfaceDescriptor *descriptor)
+ {
+ return descriptor->d;
+ }
+
+ static void setPrivate(QServiceInterfaceDescriptor *descriptor, QServiceInterfaceDescriptorPrivate *p)
+ {
+ descriptor->d = p;
+ }
+
+ QString serviceName;
+ QString interfaceName;
+ QHash<QServiceInterfaceDescriptor::Attribute, QVariant> attributes;
+ QHash<QString, QString> customAttributes;
+ int major;
+ int minor;
+ QService::Scope scope;
+};
+QTM_END_NAMESPACE
+
+#endif //QSERVICEINTERFACEDESCRIPTOR_P_H
diff --git a/src/serviceframework/qservicemanager.cpp b/src/serviceframework/qservicemanager.cpp
new file mode 100644
index 00000000..a4ce9212
--- /dev/null
+++ b/src/serviceframework/qservicemanager.cpp
@@ -0,0 +1,796 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qservicemanager.h"
+#include "qserviceplugininterface.h"
+#include "qabstractsecuritysession.h"
+#include "qserviceinterfacedescriptor_p.h"
+#include "qremoteserviceregister_p.h"
+#include "qremoteserviceregisterentry_p.h"
+
+#ifdef Q_OS_SYMBIAN
+ #include "databasemanager_symbian_p.h"
+#else
+ #include "databasemanager_p.h"
+#endif
+
+#include <QObject>
+#include <QPluginLoader>
+#include <QFile>
+#include <QCoreApplication>
+#include <QDir>
+#include <QSystemSemaphore>
+
+QTM_BEGIN_NAMESPACE
+
+static QString qservicemanager_resolveLibraryPath(const QString &libNameOrPath)
+{
+ if (QFile::exists(libNameOrPath))
+ return libNameOrPath;
+
+ // try to find plug-in via QLibrary
+ QStringList paths = QCoreApplication::libraryPaths();
+#ifdef QTM_PLUGIN_PATH
+ paths << QLatin1String(QTM_PLUGIN_PATH)+QLatin1String("/serviceframework");
+#endif
+ for (int i=0; i<paths.count(); i++) {
+ QString libPath = QDir::toNativeSeparators(paths[i]) + QDir::separator() + libNameOrPath;
+
+#ifdef Q_OS_SYMBIAN
+ QFileInfo fi(libPath);
+ if (fi.suffix() == QLatin1String("dll"))
+ libPath = fi.completeBaseName() + QLatin1String(".qtplugin");
+ else
+ libPath += QLatin1String(".qtplugin");
+
+ QLibrary lib(libPath);
+ if (QFile::exists(libPath) && lib.load()) {
+ lib.unload();
+ return libPath;
+ }
+#else
+ QLibrary lib(libPath);
+ if (lib.load()) {
+ lib.unload();
+ return lib.fileName();
+ }
+#endif
+ }
+ return QString();
+}
+
+class QServicePluginCleanup : public QObject
+{
+ Q_OBJECT
+public:
+ QServicePluginCleanup(QPluginLoader *loader, QObject *parent = 0)
+ : QObject(parent),
+ m_loader(loader)
+ {
+ }
+
+ ~QServicePluginCleanup()
+ {
+ if (m_loader) {
+ //m_loader->unload();
+ delete m_loader;
+ }
+ }
+
+ QPluginLoader *m_loader;
+};
+
+class QServiceManagerPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ QServiceManager *manager;
+ DatabaseManager *dbManager;
+ QService::Scope scope;
+ QServiceManager::Error error;
+
+ QServiceManagerPrivate(QServiceManager *parent = 0)
+ : QObject(parent),
+ manager(parent),
+ dbManager(new DatabaseManager)
+ {
+ connect(dbManager, SIGNAL(serviceAdded(QString, DatabaseManager::DbScope)),
+ SLOT(serviceAdded(QString, DatabaseManager::DbScope)));
+ connect(dbManager, SIGNAL(serviceRemoved(QString, DatabaseManager::DbScope)),
+ SLOT(serviceRemoved(QString, DatabaseManager::DbScope)));
+ }
+
+ ~QServiceManagerPrivate()
+ {
+ delete dbManager;
+ }
+
+ void setError(QServiceManager::Error err)
+ {
+ error = err;
+ }
+
+ void setError()
+ {
+ switch (dbManager->lastError().code()) {
+ case DBError::NoError:
+ error = QServiceManager::NoError;
+ break;
+ case DBError::DatabaseNotOpen:
+ case DBError::InvalidDatabaseConnection:
+ case DBError::CannotCreateDbDir:
+ case DBError::CannotOpenServiceDb:
+ case DBError::NoWritePermissions:
+ case DBError::InvalidDatabaseFile:
+ error = QServiceManager::StorageAccessError;
+ break;
+ case DBError::LocationAlreadyRegistered:
+ error = QServiceManager::ServiceAlreadyExists;
+ break;
+ case DBError::IfaceImplAlreadyRegistered:
+ error = QServiceManager::ImplementationAlreadyExists;
+ break;
+ case DBError::NotFound:
+ error = QServiceManager::ComponentNotFound;
+ break;
+ case DBError::InvalidDescriptorScope:
+ error = QServiceManager::InvalidServiceInterfaceDescriptor;
+ break;
+ case DBError::SqlError:
+ case DBError::IfaceIDNotExternal:
+ case DBError::ExternalIfaceIDFound:
+ case DBError::UnknownError:
+ error = QServiceManager::UnknownError;
+ break;
+ }
+ }
+
+private slots:
+ void serviceAdded(const QString &service, DatabaseManager::DbScope dbScope)
+ {
+ QService::Scope s = (dbScope == DatabaseManager::SystemScope ?
+ QService::SystemScope : QService::UserScope);
+ emit manager->serviceAdded(service, s);
+ }
+
+ void serviceRemoved(const QString &service, DatabaseManager::DbScope dbScope)
+ {
+ QService::Scope s = (dbScope == DatabaseManager::SystemScope ?
+ QService::SystemScope : QService::UserScope);
+ emit manager->serviceRemoved(service, s);
+ }
+};
+
+/*!
+ \class QServiceManager
+ \ingroup servicefw
+ \inmodule QtServiceFramework
+ \brief The QServiceManager class enables the loading of service plugins
+ and the (de)registration of services.
+ \since 1.0
+
+ A service is a stand-alone component that can be used by multiple clients.
+ Each service implementation must derive from QObject. Clients request a
+ reference to a service via \l loadInterface() or \l loadLocalTypedInterface().
+
+ Services are separate deliveries in the form of plug-ins. New services can be (de)registered
+ at any time via \l addService() and \l removeService() respectively. Such an event is
+ published via the \l serviceAdded() and \l serviceRemoved() signal.
+ Each service plug-in must implement QServicePluginInterface.
+
+ Each plug-in may support multiple interfaces and may even provide multiple implementations
+ for the same interface. Individual implementations are identified via
+ QServiceInterfaceDescriptor. For a more detailed explanation of services and how they relate to
+ interface and their implementations please see QServiceInterfaceDescriptor.
+
+ \sa QServicePluginInterface, QServiceContext, QAbstractSecuritySession
+*/
+
+/*!
+ \enum QServiceManager::Error
+ Defines the possible errors for the service manager.
+
+ \value NoError No error occurred.
+ \value StorageAccessError The service data storage is not accessible. This could be because the caller does not have the required permissions.
+ \value InvalidServiceLocation The service was not found at its specified \l{QServiceInterfaceDescriptor::Location}{location}.
+ \value InvalidServiceXml The XML defining the service metadata is invalid.
+ \value InvalidServiceInterfaceDescriptor The service interface descriptor is invalid, or refers to an interface implementation that cannot be accessed in the current scope.
+ \value ServiceAlreadyExists Another service has previously been registered with the same \l{QServiceInterfaceDescriptor::Location}{location}.
+ \value ImplementationAlreadyExists Another service that implements the same interface version has previously been registered.
+ \value PluginLoadingFailed The service plugin cannot be loaded.
+ \value ComponentNotFound The service or interface implementation has not been registered.
+ \value ServiceCapabilityDenied The security session does not permit service access based on its capabilities.
+ \value UnknownError An unknown error occurred.
+*/
+
+/*!
+ \fn void QServiceManager::serviceAdded(const QString& serviceName, QService::Scope scope)
+
+ This signal is emited whenever a new service with the given
+ \a serviceName has been registered with the service manager.
+ \a scope indicates where the service was added.
+
+ If the manager scope is QService::SystemScope, it will not receive
+ notifications about services added in the user scope.
+
+ \sa addService()
+ \since 1.0
+*/
+
+/*!
+ \fn void QServiceManager::serviceRemoved(const QString& serviceName, QService::Scope scope)
+
+ This signal is emited whenever a service with the given
+ \a serviceName has been deregistered with the service manager.
+ \a scope indicates where the service was added.
+
+ If the manager scope is QService::SystemScope, it will not receive
+ notifications about services removed in the user scope.
+
+ \sa removeService()
+ \since 1.0
+*/
+
+/*!
+ Creates a service manager with the given \a parent.
+
+ The scope will default to QService::UserScope.
+*/
+QServiceManager::QServiceManager(QObject *parent)
+ : QObject(parent),
+ d(new QServiceManagerPrivate(this))
+{
+ qRegisterMetaType<QService::UnrecoverableIPCError>("QService::UnrecoverableIPCError");
+ d->scope = QService::UserScope;
+}
+
+/*!
+ Creates a service manager with the given \a scope and \a parent.
+ \since 1.0
+*/
+QServiceManager::QServiceManager(QService::Scope scope, QObject *parent)
+ : QObject(parent),
+ d(new QServiceManagerPrivate(this))
+{
+ d->scope = scope;
+}
+
+/*!
+ Destroys the service manager.
+*/
+QServiceManager::~QServiceManager()
+{
+ delete d;
+}
+
+/*!
+ Returns the scope used for registering and searching of services.
+ \since 1.0
+*/
+QService::Scope QServiceManager::scope() const
+{
+ return d->scope;
+}
+
+/*!
+ Returns a list of the services that provide the interface specified by
+ \a interfaceName. If \a interfaceName is empty, this function returns
+ a list of all available services in this manager's scope.
+ \since 1.0
+*/
+QStringList QServiceManager::findServices(const QString& interfaceName) const
+{
+ d->setError(NoError);
+ QStringList services;
+ services = d->dbManager->getServiceNames(interfaceName,
+ d->scope == QService::SystemScope ? DatabaseManager::SystemScope : DatabaseManager::UserScope);
+ d->setError();
+ return services;
+}
+
+/*!
+ Returns a list of the interfaces that match the specified \a filter.
+ \since 1.0
+*/
+QList<QServiceInterfaceDescriptor> QServiceManager::findInterfaces(const QServiceFilter& filter) const
+{
+ d->setError(NoError);
+ QList<QServiceInterfaceDescriptor> descriptors = d->dbManager->getInterfaces(filter,
+ d->scope == QService::SystemScope ? DatabaseManager::SystemScope : DatabaseManager::UserScope);
+ if (descriptors.isEmpty() && d->dbManager->lastError().code() != DBError::NoError) {
+ d->setError();
+ return QList<QServiceInterfaceDescriptor>();
+ }
+ return descriptors;
+}
+
+/*!
+ Returns a list of the interfaces provided by the service named
+ \a serviceName. If \a serviceName is empty, this function returns
+ a list of all available interfaces in this manager's scope.
+ \since 1.0
+*/
+QList<QServiceInterfaceDescriptor> QServiceManager::findInterfaces(const QString& serviceName) const
+{
+ QServiceFilter filter;
+ if (!serviceName.isEmpty())
+ filter.setServiceName(serviceName);
+ return findInterfaces(filter);
+}
+
+/*!
+ Loads and returns the interface specified by \a interfaceName, as
+ provided by the default service for this interface, using the given
+ \a context and \a session. \a context and \a session object are owned
+ by the caller of this function.
+
+ The caller takes ownership of the returned pointer.
+
+ This function returns a null pointer if the requested service cannot be found.
+
+ The security session object is not mandatory. If the session pointer is null,
+ the service manager will not perform any checks. Therefore it is assumed that
+ the service manager client is trusted as it controls whether service capabilities
+ are enforced during service loading.
+
+ \sa setInterfaceDefault(), interfaceDefault()
+ \since 1.0
+*/
+QObject* QServiceManager::loadInterface(const QString& interfaceName, QServiceContext* context, QAbstractSecuritySession* session)
+{
+ return loadInterface(interfaceDefault(interfaceName), context, session);
+}
+
+/*!
+ Loads and returns the interface specified by \a descriptor using the
+ given \a context and \a session. \a context and \a session object are owned
+ by the caller of this function.
+
+ The caller takes ownership of the returned pointer.
+
+ This function returns a null pointer if the requested service cannot be found.
+
+ The security session object is not mandatory. If the session pointer is null,
+ the service manager will not perform any checks. Therefore it is assumed that
+ the service manager client is trusted as it controls whether service capabilities
+ are enforced during service loading.
+ \since 1.0
+*/
+QObject* QServiceManager::loadInterface(const QServiceInterfaceDescriptor& descriptor, QServiceContext* context, QAbstractSecuritySession* session)
+{
+ d->setError(NoError);
+ if (!descriptor.isValid()) {
+ d->setError(InvalidServiceInterfaceDescriptor);
+ return 0;
+ }
+
+ const QStringList serviceCaps = descriptor.attribute(QServiceInterfaceDescriptor::Capabilities).toStringList();
+ if ( session && !session->isAllowed(serviceCaps) ) {
+ d->setError(ServiceCapabilityDenied);
+ return 0;
+ }
+
+ const QString location = descriptor.attribute(QServiceInterfaceDescriptor::Location).toString();
+ const bool isInterProcess = (descriptor.attribute(QServiceInterfaceDescriptor::ServiceType).toInt()
+ == QService::InterProcess);
+ if (isInterProcess) {
+ //ipc service
+ const int majorversion = descriptor.majorVersion();
+ const int minorversion = descriptor.minorVersion();
+ QString version = QString::number(majorversion) + "." + QString::number(minorversion);
+
+ QRemoteServiceRegister::Entry serviceEntry;
+ serviceEntry.d->iface = descriptor.interfaceName();
+ serviceEntry.d->service = descriptor.serviceName();
+ serviceEntry.d->ifaceVersion = version;
+ QObject* service = QRemoteServiceRegisterPrivate::proxyForService(serviceEntry, location);
+ if (!service)
+ d->setError(InvalidServiceLocation);
+
+ //client owns proxy object
+ return service;
+ }
+
+ const QString serviceFilePath = qservicemanager_resolveLibraryPath(location);
+ if (serviceFilePath.isEmpty()) {
+ d->setError(InvalidServiceLocation);
+ return 0;
+ }
+
+ QPluginLoader *loader = new QPluginLoader(serviceFilePath);
+ //pluginIFace is same for all service instances of the same plugin
+ //calling loader->unload deletes pluginIFace automatically if now other
+ //service instance is around
+ QServicePluginInterface *pluginIFace = qobject_cast<QServicePluginInterface *>(loader->instance());
+ if (pluginIFace) {
+
+ //check initialization first as the service may be a pre-registered one
+ bool doLoading = true;
+ QString serviceInitialized = descriptor.customAttribute(SERVICE_INITIALIZED_ATTR);
+ if (!serviceInitialized.isEmpty() && (serviceInitialized == QLatin1String("NO"))) {
+ // open/create the semaphore using the service's name as identifier
+ QSystemSemaphore semaphore(descriptor.serviceName(), 1);
+ if (semaphore.error() != QSystemSemaphore::NoError) {
+ //try to create it
+ semaphore.setKey(descriptor.serviceName(), 1, QSystemSemaphore::Create);
+ }
+ if (semaphore.error() == QSystemSemaphore::NoError && semaphore.acquire()) {
+ pluginIFace->installService();
+ DatabaseManager::DbScope scope = d->scope == QService::UserScope ?
+ DatabaseManager::UserOnlyScope : DatabaseManager::SystemScope;
+ d->dbManager->serviceInitialized(descriptor.serviceName(), scope);
+ // release semaphore
+ semaphore.release();
+ }
+ else
+ doLoading = false;
+ }
+
+ if (doLoading) {
+ QObject *obj = pluginIFace->createInstance(descriptor, context, session);
+ if (obj) {
+ QServicePluginCleanup *cleanup = new QServicePluginCleanup(loader);
+ QObject::connect(obj, SIGNAL(destroyed()), cleanup, SLOT(deleteLater()));
+ return obj;
+ }
+ }
+ }
+
+ //loader->unload();
+ delete loader;
+ d->setError(PluginLoadingFailed);
+
+ return 0;
+}
+
+/*!
+ \fn T* QServiceManager::loadLocalTypedInterface(const QString& interfaceName, QServiceContext* context, QAbstractSecuritySession* session)
+
+ Loads the service object implementing \a interfaceName,
+ as provided by the default service for this interface, using the given
+ \a context and \a session. \a context and \a session object are owned
+ by the caller of this function. The template class must be derived from QObject.
+
+ If \a interfaceName is not a known interface the returned pointer will be null.
+
+ Note that using this function implies that service and client share
+ the implementation of T which means that service and client become tightly coupled.
+ This may cause issue during later updates as certain changes may require code changes
+ to the service and client.
+
+ The caller takes ownership of the returned pointer.
+
+ The security session object is not mandatory. If the session pointer is null,
+ the service manager will not perform any checks. Therefore it is assumed that
+ the service manager client is trusted as it controls whether service capabilities
+ are enforced during service loading.
+
+ \sa setInterfaceDefault(), interfaceDefault()
+ \since 1.0
+*/
+
+
+/*!
+ \fn T* QServiceManager::loadLocalTypedInterface(const QServiceInterfaceDescriptor& serviceDescriptor, QServiceContext* context, QAbstractSecuritySession* session)
+
+ Loads the service object identified by \a serviceDescriptor
+ using the given \a context and \a session. \a context and \a session object are owned
+ by the caller of this function. The template class must be derived from QObject.
+
+ If the \a serviceDescriptor is not valid the returned pointer will be null.
+
+ Note that using this function implies that service and client share
+ the implementation of T which means that service and client become tightly coupled.
+ This may cause issue during later updates as certain changes may require code changes
+ to the service and client.
+
+ The caller takes ownership of the returned pointer.
+
+ The security session object is not mandatory. If the session pointer is null,
+ the service manager will not perform any checks. Therefore it is assumed that
+ the service manager client is trusted as it controls whether service capabilities
+ are enforced during service loading.
+ \since 1.0
+*/
+
+/*!
+ Registers the service defined by the XML file at \a xmlFilePath.
+ Returns true if the registration succeeded, and false otherwise.
+
+ If a previously unkown interface is added the newly registered service automatically
+ becomes the new default service provider for the new interface.
+
+ A service plugin cannot be added if another service is already registered
+ with the same plugin file path. A service plugin also cannot be added if
+ the service is already registered and implements any of the same interface
+ versions that the new plugin implements.
+
+ \sa removeService(), setInterfaceDefault()
+ \since 1.0
+*/
+bool QServiceManager::addService(const QString& xmlFilePath)
+{
+ QFile *f = new QFile(xmlFilePath);
+ bool b = addService(f);
+ delete f;
+ return b;
+}
+
+/*!
+ Registers the service defined by the XML data from the given \a device.
+ Returns true if the registration succeeded, and false otherwise. If a
+ previously unkown interface is added the newly registered service
+ automatically becomes the new default service provider for the new
+ interface.
+
+ Registering a service also causes QServicePluginInterface::installService()
+ to be called on the service. If the service plugin is not accessible
+ (e.g. if the plugin file is not found) and \c installService() cannot
+ be invoked on the service, the registration fails and this method returns
+ false.
+
+ A service plugin cannot be added if another service is already registered
+ with the same plugin file path. A service plugin also cannot be added if
+ the service is already registered and implements any of the same interface
+ versions that the new plugin implements.
+
+ Services are always added based on the \l scope() of the current
+ service manager instance.
+
+ \sa removeService(), setInterfaceDefault()
+ \since 1.0
+*/
+bool QServiceManager::addService(QIODevice *device)
+{
+ d->setError(NoError);
+ ServiceMetaData parser(device);
+ if (!parser.extractMetadata()) {
+ d->setError(InvalidServiceXml);
+ return false;
+ }
+ const ServiceMetaDataResults data = parser.parseResults();
+
+ DatabaseManager::DbScope scope = d->scope == QService::UserScope ?
+ DatabaseManager::UserOnlyScope : DatabaseManager::SystemScope;
+ ServiceMetaDataResults results = parser.parseResults();
+
+ bool result = d->dbManager->registerService(results, scope);
+
+ if (results.type == QService::InterProcess)
+ return result;
+
+ //test the new plug-in
+ if (result) {
+ QPluginLoader *loader = new QPluginLoader(qservicemanager_resolveLibraryPath(data.location));
+ QServicePluginInterface *pluginIFace = qobject_cast<QServicePluginInterface *>(loader->instance());
+ if (pluginIFace) {
+ pluginIFace->installService();
+ } else {
+ d->setError(PluginLoadingFailed);
+ result = false;
+ d->dbManager->unregisterService(data.name, scope);
+ }
+ //loader->unload();
+ delete loader;
+ } else {
+ d->setError();
+ }
+
+ return result;
+}
+
+/*!
+ Unregisters the service specified by \a serviceName.
+
+ Returns true if the unregistration succeeded, and false otherwise.
+
+ If a default service implementation is removed and there are other implementations
+ for the same interface, the service manager chooses the implementation with the
+ highest version number as the new default. If there is more than one serivce
+ with the same version number, the service manager makes a random choice with
+ regards to the new default implementation. If this is
+ not the desired behaviour the default selection should be updated
+ via setInterfaceDefault().
+
+ Services are always removed based on the \l scope() of the current
+ service manager instance.
+
+ \sa addService()
+ \since 1.0
+*/
+bool QServiceManager::removeService(const QString& serviceName)
+{
+ d->setError(NoError);
+ if (serviceName.isEmpty()) {
+ d->setError(ComponentNotFound);
+ return false;
+ }
+
+ // Call QServicePluginInterface::uninstallService() on all plugins that
+ // match this service
+
+ QSet<QString> pluginPathsSet;
+ QList<QServiceInterfaceDescriptor> descriptors = findInterfaces(serviceName);
+ for (int i=0; i<descriptors.count(); i++) {
+ const QString loc = descriptors[i].attribute(QServiceInterfaceDescriptor::Location).toString();
+ const int type = descriptors[i].attribute(QServiceInterfaceDescriptor::ServiceType).toInt();
+ //exclude ipc services
+ if (type <= QService::Plugin)
+ pluginPathsSet << loc;
+ }
+
+ QList<QString> pluginPaths = pluginPathsSet.toList();
+ for (int i=0; i<pluginPaths.count(); i++) {
+ QPluginLoader *loader = new QPluginLoader(qservicemanager_resolveLibraryPath(pluginPaths[i]));
+ QServicePluginInterface *pluginIFace = qobject_cast<QServicePluginInterface *>(loader->instance());
+ if (pluginIFace)
+ pluginIFace->uninstallService();
+ else
+ qWarning() << "QServiceManager: unable to invoke uninstallService() on removed service";
+ //loader->unload();
+ delete loader;
+ }
+
+ if (!d->dbManager->unregisterService(serviceName, d->scope == QService::UserScope ?
+ DatabaseManager::UserOnlyScope : DatabaseManager::SystemScope)) {
+ d->setError();
+ return false;
+ }
+ return true;
+}
+
+/*!
+ Sets the default interface implementation for \a interfaceName to the
+ matching interface implementation provided by \a service.
+
+ If \a service provides more than one interface implementation for
+ \a interfaceName, the newest version of the interface is set as the
+ default.
+
+ Returns true if the operation succeeded, and false otherwise.
+
+ \bold {Note:} When in system scope, the \a service must be a system-wide
+ service rather than a user-specific service; otherwise, this will fail.
+ \since 1.0
+*/
+bool QServiceManager::setInterfaceDefault(const QString &service, const QString &interfaceName)
+{
+ d->setError(NoError);
+ if (service.isEmpty() || interfaceName.isEmpty()) {
+ d->setError(ComponentNotFound);
+ return false;
+ }
+ DatabaseManager::DbScope scope = d->scope == QService::SystemScope ?
+ DatabaseManager::SystemScope : DatabaseManager::UserScope;
+ if (!d->dbManager->setInterfaceDefault(service, interfaceName, scope)) {
+ d->setError();
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \overload
+
+ Sets the interface implementation specified by \a descriptor to be the
+ default implementation for the particular interface specified in the
+ descriptor.
+
+ Returns true if the operation succeeded, and false otherwise.
+
+ \bold {Note:} When in system scope, the \a descriptor must refer to a
+ system-wide service rather than a user-specific service; otherwise, this
+ will fail.
+ \since 1.0
+*/
+bool QServiceManager::setInterfaceDefault(const QServiceInterfaceDescriptor& descriptor)
+{
+ d->setError(NoError);
+ DatabaseManager::DbScope scope = d->scope == QService::SystemScope ?
+ DatabaseManager::SystemScope : DatabaseManager::UserScope;
+ if (!d->dbManager->setInterfaceDefault(descriptor, scope)) {
+ d->setError();
+ return false;
+ }
+ return true;
+}
+
+/*!
+ Returns the default interface implementation for the given \a interfaceName.
+ \since 1.0
+*/
+QServiceInterfaceDescriptor QServiceManager::interfaceDefault(const QString& interfaceName) const
+{
+ d->setError(NoError);
+ DatabaseManager::DbScope scope = d->scope == QService::SystemScope ?
+ DatabaseManager::SystemScope : DatabaseManager::UserScope;
+ QServiceInterfaceDescriptor info = d->dbManager->interfaceDefault(interfaceName, scope);
+ if (d->dbManager->lastError().code() != DBError::NoError) {
+ d->setError();
+ return QServiceInterfaceDescriptor();
+ }
+ return info;
+}
+
+/*!
+ Returns the type of error that last occurred.
+ \since 1.0
+*/
+QServiceManager::Error QServiceManager::error() const
+{
+ return d->error;
+}
+
+/*!
+ \internal
+ \since 1.0
+*/
+void QServiceManager::connectNotify(const char *signal)
+{
+ if (QLatin1String(signal) == SIGNAL(serviceAdded(QString,QService::Scope))
+ || QLatin1String(signal) == SIGNAL(serviceRemoved(QString,QService::Scope))) {
+ if (d->scope != QService::SystemScope)
+ d->dbManager->setChangeNotificationsEnabled(DatabaseManager::UserScope, true);
+ d->dbManager->setChangeNotificationsEnabled(DatabaseManager::SystemScope, true);
+ }
+}
+
+/*!
+ \internal
+ \since 1.0
+*/
+void QServiceManager::disconnectNotify(const char *signal)
+{
+ if (QLatin1String(signal) == SIGNAL(serviceAdded(QString,QService::Scope))
+ || QLatin1String(signal) == SIGNAL(serviceRemoved(QString,QService::Scope))) {
+ if (receivers(SIGNAL(serviceAdded(QString,QService::Scope))) == 0
+ && receivers(SIGNAL(serviceRemoved(QString,QService::Scope))) == 0) {
+ if (d->scope != QService::SystemScope)
+ d->dbManager->setChangeNotificationsEnabled(DatabaseManager::UserScope, false);
+ d->dbManager->setChangeNotificationsEnabled(DatabaseManager::SystemScope, false);
+ }
+ }
+}
+
+#include "moc_qservicemanager.cpp"
+#include "qservicemanager.moc"
+QTM_END_NAMESPACE
+
diff --git a/src/serviceframework/qservicemanager.h b/src/serviceframework/qservicemanager.h
new file mode 100644
index 00000000..af14eca6
--- /dev/null
+++ b/src/serviceframework/qservicemanager.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERVICEMANAGER_H
+#define QSERVICEMANAGER_H
+
+#include "qserviceframeworkglobal.h"
+
+#include "qservice.h"
+#include "qserviceinterfacedescriptor.h"
+#include "qservicefilter.h"
+
+#include <QObject>
+#include <QList>
+#include <QStringList>
+#include <QDebug>
+
+
+QT_BEGIN_HEADER
+
+QTM_BEGIN_NAMESPACE
+
+class QServiceContext;
+class QAbstractSecuritySession;
+class QServiceFilter;
+class QServiceManagerPrivate;
+class Q_SERVICEFW_EXPORT QServiceManager : public QObject
+{
+ Q_OBJECT
+public:
+
+ enum Error {
+ NoError,
+ StorageAccessError,
+ InvalidServiceLocation,
+ InvalidServiceXml,
+ InvalidServiceInterfaceDescriptor,
+ ServiceAlreadyExists,
+ ImplementationAlreadyExists,
+ PluginLoadingFailed,
+ ComponentNotFound,
+ ServiceCapabilityDenied,
+ UnknownError = 100
+ };
+
+ explicit QServiceManager(QObject *parent = 0);
+ explicit QServiceManager(QService::Scope scope, QObject *parent = 0);
+ ~QServiceManager();
+
+ QService::Scope scope() const;
+
+ QStringList findServices(const QString& interfaceName = QString()) const;
+ QList<QServiceInterfaceDescriptor> findInterfaces(const QServiceFilter& filter = QServiceFilter()) const;
+ QList<QServiceInterfaceDescriptor> findInterfaces(const QString& serviceName) const;
+
+ QObject* loadInterface(const QString& interfaceName, QServiceContext* context = 0, QAbstractSecuritySession* session = 0);
+ QObject* loadInterface(const QServiceInterfaceDescriptor& descriptor, QServiceContext* context = 0, QAbstractSecuritySession* session = 0);
+
+ template <class T>
+ T* loadLocalTypedInterface(const QString& interfaceName, QServiceContext* context = 0, QAbstractSecuritySession* session = 0)
+ {
+ return loadLocalTypedInterface<T>(interfaceDefault(interfaceName), context, session);
+ }
+
+ template <class T>
+ T* loadLocalTypedInterface(const QServiceInterfaceDescriptor& descriptor, QServiceContext* context = 0, QAbstractSecuritySession* session = 0)
+ {
+ T* instance = 0;
+ if (descriptor.isValid()) {
+ QObject* obj = loadInterface(descriptor, context, session);
+ if (!obj) return 0;
+
+ //TODO this should really be
+ //instance = qobject_cast<T *>(loadInterface(descriptor, context, session));
+ //check why qobject_cast fails
+ const char* templateClassName = reinterpret_cast<T *>(0)->staticMetaObject.className();
+ const QMetaObject* source = obj->metaObject();
+ do {
+ if (strcmp(templateClassName,source->className())==0) {
+ instance = static_cast<T *>(obj);
+ break;
+ }
+ source = source->superClass();
+ } while (source != 0);
+ if (!instance)
+ delete obj;
+ }
+ return instance;
+ }
+
+ bool addService(const QString& xmlFilePath);
+ bool addService(QIODevice* xmlDevice);
+ bool removeService(const QString& serviceName);
+
+ bool setInterfaceDefault(const QString &service, const QString &interfaceName);
+ bool setInterfaceDefault(const QServiceInterfaceDescriptor& descriptor);
+
+ QServiceInterfaceDescriptor interfaceDefault(const QString& interfaceName) const;
+
+ Error error() const;
+
+protected:
+ void connectNotify(const char *signal);
+ void disconnectNotify(const char *signal);
+
+Q_SIGNALS:
+ void serviceAdded(const QString& serviceName, QService::Scope scope);
+ void serviceRemoved(const QString& serviceName, QService::Scope scope);
+
+private:
+ friend class QServiceManagerPrivate;
+ QServiceManagerPrivate* d;
+};
+
+
+QTM_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/serviceframework/qserviceplugininterface.cpp b/src/serviceframework/qserviceplugininterface.cpp
new file mode 100644
index 00000000..e5b4d60a
--- /dev/null
+++ b/src/serviceframework/qserviceplugininterface.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qserviceplugininterface.h"
+
+QTM_BEGIN_NAMESPACE
+/*!
+ \class QServicePluginInterface
+ \ingroup servicefw
+ \inmodule QtServiceFramework
+ \brief The QServicePluginInterface class defines the interface
+ that every plug-in based service must implement.
+ \since 1.0
+*/
+
+/*!
+ \internal
+ \since 1.0
+*/
+QServicePluginInterface::QServicePluginInterface()
+{
+}
+
+/*!
+ \internal
+ \since 1.0
+*/
+QServicePluginInterface::~QServicePluginInterface()
+{
+}
+
+/*!
+ \fn QObject* QServicePluginInterface::createInstance(const QServiceInterfaceDescriptor& descriptor, QServiceContext* context,
+ QAbstractSecuritySession* securitySession)
+
+ Creates a new instance of the service specified by \a descriptor. The service
+ may use the given \a context and \a securitySession. \a context and \a securitySession object are owned
+ by the client of the service.
+
+ This function returns a null pointer if the plug-in doesn't
+ support the given \a descriptor.
+ \since 1.0
+*/
+
+/*!
+ \fn bool QServicePluginInterface::installService()
+
+ This function is called by QServiceManager as part of the service registration process. It can be
+ used to initialize the environment or the creation of external settings files which may be required
+ during the execution of the service.
+
+ The default implementation for this function does nothing.
+
+ \sa QServiceManager::addService()
+ \since 1.0
+*/
+void QServicePluginInterface::installService()
+{
+}
+
+/*!
+ \fn bool QServicePluginInterface::uninstallService()
+
+ This function is called bu QServiceManager as part of the deregistration process for services. This
+ gives the service the possibility to perform cleanup operations such as the removal of setting files
+ on the hard drive.
+
+ The default implementation for this function does nothing.
+
+ \sa QServiceManager::removeService()
+ \since 1.0
+*/
+
+void QServicePluginInterface::uninstallService()
+{
+}
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/qserviceplugininterface.h b/src/serviceframework/qserviceplugininterface.h
new file mode 100644
index 00000000..0c765b5d
--- /dev/null
+++ b/src/serviceframework/qserviceplugininterface.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERVICEPLUGININTERFACE_H
+#define QSERVICEPLUGININTERFACE_H
+
+#include "qserviceframeworkglobal.h"
+#include <QtPlugin>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+
+class QServiceInterfaceDescriptor;
+class QServiceContext;
+class QAbstractSecuritySession;
+
+class Q_SERVICEFW_EXPORT QServicePluginInterface
+{
+public:
+ QServicePluginInterface();
+ virtual ~QServicePluginInterface();
+
+ virtual QObject* createInstance(const QServiceInterfaceDescriptor& descriptor,
+ QServiceContext* context,
+ QAbstractSecuritySession* session) = 0;
+
+ virtual void installService();
+ virtual void uninstallService();
+};
+
+//moc doesn't understand QTM_PREPEND_NAMESPACE() macro. we have to be explicit
+//Q_DECLARE_INTERFACE(QTM_PREPEND_NAMESPACE(QServicePluginInterface), "com.nokia.qt.QServicePluginInterface/1.0")
+Q_DECLARE_INTERFACE(QServicePluginInterface, "com.nokia.qt.QServicePluginInterface/1.0")
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif
diff --git a/src/serviceframework/servicedatabase.cpp b/src/serviceframework/servicedatabase.cpp
new file mode 100644
index 00000000..d564701f
--- /dev/null
+++ b/src/serviceframework/servicedatabase.cpp
@@ -0,0 +1,2328 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// #define QT_SFW_SERVICEDATABASE_DEBUG
+
+#include "servicedatabase_p.h"
+#include <QDir>
+#include <QSet>
+#include "qserviceinterfacedescriptor.h"
+#include "qserviceinterfacedescriptor_p.h"
+#include <QUuid>
+#include "dberror_p.h"
+
+//database name
+#define RESOLVERDATABASE "services.db"
+
+//database table names
+#define SERVICE_TABLE "Service"
+#define INTERFACE_TABLE "Interface"
+#define DEFAULTS_TABLE "Defaults"
+#define SERVICE_PROPERTY_TABLE "ServiceProperty"
+#define INTERFACE_PROPERTY_TABLE "InterfaceProperty"
+
+//separator
+#define RESOLVERDATABASE_PATH_SEPARATOR "//"
+
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+#include <QDebug>
+#endif
+
+#define SERVICE_DESCRIPTION_KEY "DESCRIPTION"
+#ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+#define SECURITY_TOKEN_KEY "SECURITYTOKEN"
+#endif
+#define INTERFACE_DESCRIPTION_KEY "DESCRIPTION"
+#define SERVICE_INITIALIZED_KEY SERVICE_INITIALIZED_ATTR
+#define INTERFACE_CAPABILITY_KEY "CAPABILITIES"
+#define INTERFACE_SERVICETYPE_KEY "SERVICETYPE"
+
+//service prefixes
+#define SERVICE_IPC_PREFIX "_q_ipc_addr:"
+
+QTM_BEGIN_NAMESPACE
+
+enum TBindIndexes
+ {
+ EBindIndex=0,
+ EBindIndex1,
+ EBindIndex2,
+ EBindIndex3,
+ EBindIndex4,
+ EBindIndex5,
+ EBindIndex6,
+ EBindIndex7
+ };
+
+
+/*
+ \class ServiceDatabase
+ The ServiceDatabase is responsible for the management of a single
+ service database. It provides operations for:
+ - opening and closing a connection with the database,
+ - registering and unregistering services
+ - querying for services and interfaces
+ - setting and getting default interface implementations.
+*/
+
+/*
+ Constructor
+*/
+ServiceDatabase::ServiceDatabase(void)
+:m_isDatabaseOpen(false),m_inTransaction(false)
+{
+}
+
+/*
+ Destructor
+*/
+ServiceDatabase::~ServiceDatabase()
+{
+ close();
+}
+
+/*
+ Opens the service database
+ The method creates or opens database and creates tables if they are not present
+ Returns true if the operation was successful, false if not.
+*/
+bool ServiceDatabase::open()
+{
+ if (m_isDatabaseOpen)
+ return true;
+
+ QString path;
+
+ //Create full path to database
+ if (m_databasePath.isEmpty ())
+ m_databasePath = databasePath();
+
+ path = m_databasePath;
+ QFileInfo dbFileInfo(path);
+ if (!dbFileInfo.dir().exists()) {
+ // Create the path with QFile, avoids problems with S60 3.2/3.1
+ // Avoid security violation with PlatSec
+#ifndef Q_OS_SYMBIAN
+ QDir::root().mkpath(dbFileInfo.path());
+#endif
+ QFile file(path);
+ if (!file.open(QIODevice::ReadWrite)) {
+ QString errorText(QLatin1String("Could not create database directory: %1"));
+ m_lastError.setError(DBError::CannotCreateDbDir, errorText.arg(dbFileInfo.path()));
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::open():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ close();
+ return false;
+ }
+ file.close();
+ }
+
+ m_connectionName = dbFileInfo.completeBaseName();
+ QSqlDatabase database;
+ if (QSqlDatabase::contains(m_connectionName)) {
+ database = QSqlDatabase::database(m_connectionName);
+ } else {
+ database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), m_connectionName);
+ database.setDatabaseName(path);
+ }
+
+ if (!database.isValid()){
+ m_lastError.setError(DBError::InvalidDatabaseConnection);
+ close();
+ return false;
+ }
+
+ //Create or open database
+ if (!database.isOpen()) {
+ if (!database.open()) {
+ m_lastError.setError(DBError::SqlError, database.lastError().text());
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::open():-"
+ << "Problem:" << "Could not open database. "
+ << "Reason:" << m_lastError.text();
+#endif
+ close();
+ return false;
+ }
+ }
+ m_isDatabaseOpen = true;
+
+ //Check database structure (tables) and recreate tables if neccessary
+ //If one of tables is missing remove all tables and recreate them
+ //This operation is required in order to avoid data coruption
+ if (!checkTables()) {
+ if (dropTables()) {
+ if (createTables()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qDebug() << "ServiceDatabase::open():-"
+ << "Database tables recreated";
+#endif
+ } else {
+ //createTable() should've handled error message
+ //and warning
+ close();
+ return false;
+ }
+ }
+ else {
+ //dropTables() should've handled error message
+ //and warning
+ close();
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ Adds a \a service into the database.
+
+ May set the following error codes
+ DBError::NoError
+ DBError::LocationAlreadyRegistered
+ DBError::IfaceImplAlreadyRegistered
+ DBError::SqlError
+ DBError::DatabaseNotOpen
+ DBError::InvalidDatabaseConnection
+ DBError::NoWritePermissions
+ DBError::InvalidDatabaseFile
+*/
+//bool ServiceDatabase::registerService(ServiceMetaData &service)
+bool ServiceDatabase::registerService(const ServiceMetaDataResults &service, const QString &securityToken)
+{
+ // Derive the location name with the service type prefix to be stored
+ QString locationPrefix = service.location;
+ int type = service.interfaces[0].d->attributes[QServiceInterfaceDescriptor::ServiceType].toInt();
+ if (type == QService::InterProcess)
+ locationPrefix = SERVICE_IPC_PREFIX + service.location;
+
+#ifndef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+ Q_UNUSED(securityToken);
+#else
+ if (securityToken.isEmpty()) {
+ QString errorText("Access denied, no security token provided (for registering service: \"%1\")");
+ m_lastError.setError(DBError::NoWritePermissions, errorText.arg(service.name));
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << "Problem: Unable to register service,"
+ << "reason:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+#endif
+
+ if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+ QSqlQuery query(database);
+
+ if (!beginTransaction(&query, Write)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << "Unable to begin transaction,"
+ << "reason:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ //See if the service's location has already been previously registered
+ QString statement(QLatin1String("SELECT Name from Service WHERE Location=? COLLATE NOCASE"));
+ QList<QVariant> bindValues;
+ bindValues.append(locationPrefix);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ if (query.next()) {
+ QString alreadyRegisteredService = query.value(EBindIndex).toString();
+ const QString errorText = QLatin1String("Cannot register service \"%1\". Service location \"%2\" is already "
+ "registered to service \"%3\". \"%3\" must first be deregistered "
+ "for new registration to take place.");
+
+ m_lastError.setError(DBError::LocationAlreadyRegistered,
+ errorText.arg(service.name)
+ .arg(service.location)
+ .arg(alreadyRegisteredService));
+
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+#ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+ // If service(s) have already been registered with same name, they must all come from
+ // same application. Fetch a service with given name and if such exists, check that its
+ // security ID equals to the security ID of the current registrar.
+ // One application may register multiple services with same name (different location),
+ // hence the keyword DISTINCT.
+ statement = "SELECT DISTINCT ServiceProperty.Value FROM Service, ServiceProperty "
+ "WHERE Service.ID = ServiceProperty.ServiceID "
+ "AND ServiceProperty.Key = ? "
+ "AND Service.Name = ?";
+ bindValues.clear();
+ bindValues.append(SECURITY_TOKEN_KEY);
+ bindValues.append(service.name);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ QString existingSecurityToken;
+ if (query.next()) {
+ existingSecurityToken = query.value(EBindIndex).toString();
+ }
+ if (!existingSecurityToken.isEmpty() && (existingSecurityToken != securityToken)) {
+ QString errorText("Access denied: \"%1\"");
+ m_lastError.setError(DBError::NoWritePermissions, errorText.arg(service.name));
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << "Problem: Unable to register service,"
+ << "reason:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+#endif // QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+
+ // Checks done, create new rows into tables.
+ statement = QLatin1String("INSERT INTO Service(ID,Name,Location) VALUES(?,?,?)");
+
+ qsrand(QTime::currentTime().msec());
+ QString serviceID = QUuid::createUuid().toString();
+
+ bindValues.clear();
+ bindValues.append(serviceID);
+ bindValues.append(service.name);
+ bindValues.append(locationPrefix);
+
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ statement = QLatin1String("INSERT INTO ServiceProperty(ServiceID,Key,Value) VALUES(?,?,?)");
+ bindValues.clear();
+ bindValues.append(serviceID);
+ bindValues.append(QLatin1String(SERVICE_DESCRIPTION_KEY));
+ if (service.description.isNull())
+ bindValues.append(QLatin1String(""));
+ else
+ bindValues.append(service.description);
+
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+#ifdef QT_SFW_SERVICEDATABASE_GENERATE
+ statement = "INSERT INTO ServiceProperty(ServiceId,Key,Value) VALUES(?,?,?)";
+ bindValues.clear();
+ bindValues.append(serviceID);
+ bindValues.append(SERVICE_INITIALIZED_KEY);
+ bindValues.append(QString("NO"));
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+#endif
+
+#ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+ // Insert a security token for the particular service
+ statement = "INSERT INTO ServiceProperty(ServiceID,Key,Value) VALUES(?,?,?)";
+ bindValues.clear();
+ bindValues.append(serviceID);
+ bindValues.append(SECURITY_TOKEN_KEY);
+ bindValues.append(securityToken);
+
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+#endif // QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+
+ QList <QServiceInterfaceDescriptor> interfaces = service.interfaces;
+ QString interfaceID;;
+ foreach (const QServiceInterfaceDescriptor &interface, interfaces) {
+ interfaceID = getInterfaceID(&query, interface);
+ if (m_lastError.code() == DBError::NoError) {
+ QString errorText;
+ errorText = QLatin1String("Cannot register service \"%1\". \"%1\" is already registered "
+ "and implements interface \"%2\", Version \"%3.%4.\" \"%1\" must "
+ "first be deregistered for new registration to take place.");
+ m_lastError.setError(DBError::IfaceImplAlreadyRegistered,
+ errorText.arg(interface.serviceName())
+ .arg(interface.interfaceName())
+ .arg(interface.majorVersion())
+ .arg(interface.minorVersion()));
+
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ } else if (m_lastError.code() == DBError::NotFound){
+ //No interface implementation already exists for the service
+ //so add it
+ if (!insertInterfaceData(&query, interface, serviceID)) {
+ rollbackTransaction(&query);
+ return false;
+ } else {
+ continue;
+ }
+ } else {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << "Unable to confirm if implementation version"
+ << (QString::number(interface.majorVersion()) + "."
+ + QString::number(interface.minorVersion())).toAscii()
+ << "for interface" << interface.interfaceName()
+ << "is already registered for service "
+ << interface.serviceName()
+ << qPrintable(QString("\n") + m_lastError.text());
+#endif
+ return false;
+ }
+ }
+
+ interfaces = service.latestInterfaces;
+ QServiceInterfaceDescriptor defaultInterface;
+ foreach (const QServiceInterfaceDescriptor &interface, interfaces) {
+ defaultInterface = interfaceDefault(interface.interfaceName(), NULL, true);
+ if (m_lastError.code() == DBError::NoError
+ || m_lastError.code() == DBError::ExternalIfaceIDFound) {
+ continue; //default already exists so don't do anything
+ } else if (m_lastError.code() == DBError::NotFound) {
+ //default does not already exist so create one
+ interfaceID = getInterfaceID(&query, interface);
+ if (m_lastError.code() != DBError::NoError) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << "Unable to retrieve interfaceID for "
+ "interface" << interface.interfaceName()
+ << qPrintable(QString("\n") + m_lastError.text());
+#endif
+ return false;
+ }
+
+ statement = QLatin1String("INSERT INTO Defaults(InterfaceName, InterfaceID) VALUES(?,?)");
+ bindValues.clear();
+ bindValues.append(interface.interfaceName());
+ bindValues.append(interfaceID);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ } else {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::registerService()"
+ << "Problem: Unable to confirm if interface"
+ << interface.interfaceName()
+ << "already has a default implementation";
+#endif
+ return false;
+ }
+ }
+
+ if (!commitTransaction(&query)) {
+ rollbackTransaction(&query);
+ return false;
+ }
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+/*
+ Obtains an interface ID corresponding to a given interface \a descriptor
+
+ May set the following error codes:
+ DBError::NoError
+ DBError::NotFound
+ DBError::SqlError
+ DBError::DatabaseNotOpen
+ DBError::InvalidDatabaseConnection
+*/
+QString ServiceDatabase::getInterfaceID(const QServiceInterfaceDescriptor &descriptor) {
+ QString interfaceID;
+ if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::getInterfaceID():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return interfaceID;
+ }
+
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+ QSqlQuery query(database);
+
+ return getInterfaceID(&query, descriptor);
+}
+
+/*
+ This function should only ever be called on a user scope database.
+ It returns a list of Interface Name and Interface ID pairs, where
+ the Interface ID refers to an external interface implementation
+ in the system scope database.
+
+ May set the last error to:
+ DBError::NoError
+ DBError::SqlError
+ DBError::DatabaseNotOpen
+ DBError::InvalidDatabaseConnection
+
+ Aside: There is only one query which implicitly gets
+ wrapped in it's own transaction.
+*/
+QList<QPair<QString,QString> > ServiceDatabase::externalDefaultsInfo()
+{
+ QList<QPair<QString,QString> > ret;
+ if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::externalDefaultsInfo():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return ret;
+ }
+
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+ QSqlQuery query(database);
+
+ //Prepare search query, bind criteria values and execute search
+ QString selectComponent = QLatin1String("SELECT InterfaceName, InterfaceID ");
+ QString fromComponent = QLatin1String("FROM Defaults ");
+ QString whereComponent = QLatin1String("WHERE InterfaceID NOT IN (SELECT Interface.ID FROM Interface) ");
+
+ //Aside: this individual query is implicitly wrapped in a transaction
+ if (!executeQuery(&query, selectComponent + fromComponent + whereComponent)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::externalDefaultsInfo():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return ret;
+ }
+
+ while (query.next()) {
+ ret.append(qMakePair(query.value(EBindIndex).toString(),
+ query.value(EBindIndex1).toString()));
+ }
+
+ m_lastError.setError(DBError::NoError);
+ return ret;
+}
+
+/*
+ Helper function that obtains an interfaceID for a given \a descriptor.
+
+ May set last error to one of the following error codes:
+ DBError::NoError
+ DBError::NotFound
+ DBError::SqlError
+
+ Aside: This function may be safely called standalone or within an explicit
+ transaction. If called standalone, it's single query is implicitly
+ wrapped in it's own transaction.
+*/
+QString ServiceDatabase::getInterfaceID(QSqlQuery *query, const QServiceInterfaceDescriptor &interface)
+{
+ QString statement = QLatin1String("SELECT Interface.ID "
+ "FROM Interface, Service "
+ "WHERE Service.ID = Interface.ServiceID "
+ "AND Service.Name = ? COLLATE NOCASE "
+ "AND Interface.Name = ? COLLATE NOCASE "
+ "AND Interface.VerMaj = ? AND Interface.VerMin = ?");
+ QList<QVariant> bindValues;
+ bindValues.append(interface.serviceName());
+ bindValues.append(interface.interfaceName());
+ bindValues.append(interface.majorVersion());
+ bindValues.append(interface.minorVersion());
+
+ if (!executeQuery(query, statement, bindValues)) {
+ return QString();
+ }
+
+ if (!query->next()) {
+ QString errorText(QLatin1String("No Interface Descriptor found with "
+ "Service name: %1 "
+ "Interface name: %2 "
+ "Version: %3.%4"));
+ m_lastError.setError(DBError::NotFound, errorText.arg(interface.serviceName())
+ .arg(interface.interfaceName())
+ .arg(interface.majorVersion())
+ .arg(interface.minorVersion()));
+ return QString();
+ }
+
+ m_lastError.setError(DBError::NoError);
+ return query->value(EBindIndex).toString();
+}
+
+/*
+ Helper functions that saves \a interface related data in the Interface table
+ The \a interface data is recorded as belonging to the service assocciated
+ with \a serviceID.
+
+ May set the last error to one of the following error codes:
+ DBError::NoError
+ DBError::SqlError
+
+ Aside: It is already assumed that a write transaction has been started by the
+ time this function is called; and this function will not rollback/commit
+ the transaction.
+*/
+bool ServiceDatabase::insertInterfaceData(QSqlQuery *query,const QServiceInterfaceDescriptor &interface, const QString &serviceID)
+{
+ QString statement = QLatin1String("INSERT INTO Interface(ID, ServiceID,Name,VerMaj, VerMin) "
+ "VALUES(?,?,?,?,?)");
+ QString interfaceID = QUuid::createUuid();
+
+ QList<QVariant> bindValues;
+ bindValues.append(interfaceID);
+ bindValues.append(serviceID);
+ bindValues.append(interface.interfaceName());
+ bindValues.append(interface.majorVersion());
+ bindValues.append(interface.minorVersion());
+
+ if (!executeQuery(query, statement, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::insertInterfaceData():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ statement = QLatin1String("INSERT INTO InterfaceProperty(InterfaceID, Key, Value) VALUES(?,?,?)");
+ QHash<QServiceInterfaceDescriptor::Attribute, QVariant>::const_iterator iter = interface.d->attributes.constBegin();
+ bool isValidInterfaceProperty;
+ QString capabilities;
+ QString interfaceDescription;
+ while (iter != interface.d->attributes.constEnd()) {
+ isValidInterfaceProperty = true;
+
+ bindValues.clear();
+ bindValues.append(interfaceID);
+ switch (iter.key()) {
+ case (QServiceInterfaceDescriptor::Capabilities):
+ bindValues.append(QLatin1String(INTERFACE_CAPABILITY_KEY));
+ capabilities = interface.attribute(QServiceInterfaceDescriptor::Capabilities).toStringList().join(QLatin1String(","));
+ if (capabilities.isNull())
+ capabilities = QLatin1String("");
+ bindValues.append(capabilities);
+ break;
+ case(QServiceInterfaceDescriptor::Location):
+ isValidInterfaceProperty = false;
+ break;
+ case(QServiceInterfaceDescriptor::ServiceDescription):
+ isValidInterfaceProperty = false;
+ break;
+ case(QServiceInterfaceDescriptor::InterfaceDescription):
+ bindValues.append(QLatin1String(INTERFACE_DESCRIPTION_KEY));
+ interfaceDescription = interface.attribute(QServiceInterfaceDescriptor::InterfaceDescription).toString();
+ if (interfaceDescription.isNull())
+ interfaceDescription = QLatin1String("");
+ bindValues.append(interfaceDescription);
+ break;
+ default:
+ isValidInterfaceProperty = false;
+ break;
+ }
+
+ if (isValidInterfaceProperty) {
+ if (!executeQuery(query, statement, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::insertInterfaceData():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ }
+ ++iter;
+ }
+
+ //add custom attributes
+ QHash<QString, QString>::const_iterator customIter = interface.d->customAttributes.constBegin();
+ while (customIter!=interface.d->customAttributes.constEnd()) {
+ bindValues.clear();
+ bindValues.append(interfaceID);
+ //to avoid key clashes use separate c_ namespace ->is this sufficient?
+ bindValues.append(QVariant("c_"+customIter.key()));
+ bindValues.append(customIter.value());
+ if (!executeQuery(query, statement, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::insertInterfaceData(customProps):-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ ++customIter;
+ }
+ m_lastError.setError(DBError::NoError);
+
+ return true;
+}
+
+/*
+ Helper function that executes the sql query specified in \a statement.
+ It is assumed that the \a statement uses positional placeholders and
+ corresponding parameters are placed in the list of \a bindValues.
+
+ Aside: This function may be safely called standalone or within an explicit
+ transaction. If called standalone, it's single query is implicitly
+ wrapped in it's own transaction.
+
+ May set the last error to one of the following error codes:
+ DBError::NoError
+ DBError::SqlError
+ DBError::NoWritePermissions
+ DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::executeQuery(QSqlQuery *query, const QString &statement, const QList<QVariant> &bindValues)
+{
+ Q_ASSERT(query != NULL);
+
+ bool success = false;
+ enum {Prepare =0 , Execute=1};
+ for (int stage=Prepare; stage <= Execute; ++stage) {
+ if ( stage == Prepare)
+ success = query->prepare(statement);
+ else // stage == Execute
+ success = query->exec();
+
+ if (!success) {
+ QString errorText;
+ errorText = QLatin1String("Problem: Could not %1 statement: %2"
+ "Reason: %3"
+ "Parameters: %4\n");
+ QString parameters;
+ if (bindValues.count() > 0) {
+ for(int i = 0; i < bindValues.count(); ++i) {
+ parameters.append(QLatin1String("\n\t[") + QString::number(i) + "]: " + bindValues.at(i).toString());
+ }
+ } else {
+ parameters = QLatin1String("None");
+ }
+
+ DBError::ErrorCode errorType;
+ int result = query->lastError().number();
+ if (result == 26 || result == 11) {//SQLILTE_NOTADB || SQLITE_CORRUPT
+ qWarning() << "Service Framework:- Database file is corrupt or invalid:" << databasePath();
+ errorType = DBError::InvalidDatabaseFile;
+ }
+ else if ( result == 8) //SQLITE_READONLY
+ errorType = DBError::NoWritePermissions;
+ else
+ errorType = DBError::SqlError;
+
+ m_lastError.setError(errorType,
+ errorText
+ .arg(stage == Prepare ?QLatin1String("prepare"):QLatin1String("execute"))
+ .arg(statement)
+ .arg(query->lastError().text())
+ .arg(parameters));
+
+ query->finish();
+ query->clear();
+ return false;
+ }
+
+ if (stage == Prepare) {
+ foreach (const QVariant &bindValue, bindValues)
+ query->addBindValue(bindValue);
+ }
+ }
+
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+/*
+ Obtains a list of QServiceInterfaceDescriptors that match the constraints supplied
+ by \a filter.
+
+ May set last error to one of the following error codes:
+ DBError::NoError
+ DBError::SqlError
+ DBError::DatabaseNotOpen
+ DBError::InvalidDatabaseConnection
+ DBError::NoWritePermissions
+ DBError::InvalidDatabaseFile
+*/
+QList<QServiceInterfaceDescriptor> ServiceDatabase::getInterfaces(const QServiceFilter &filter)
+{
+ QList<QServiceInterfaceDescriptor> interfaces;
+ if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::getInterfaces():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return interfaces;
+ }
+
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+ QSqlQuery query(database);
+
+ //multiple read queries are performed so wrap them
+ //in a read only transaction
+ if (!beginTransaction(&query, Read)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::getInterfaces():-"
+ << "Unable to begin transaction. "
+ << "Reason:" << qPrintable(m_lastError.text());
+#endif
+ return interfaces;
+ }
+
+ //Prepare search query, bind criteria values
+ QString selectComponent = QLatin1String("SELECT Interface.Name, "
+ "Service.Name, Interface.VerMaj, "
+ "Interface.VerMin, "
+ "Service.Location, "
+ "Service.ID, "
+ "Interface.ID ");
+ QString fromComponent = QLatin1String("FROM Interface, Service ");
+ QString whereComponent = QLatin1String("WHERE Service.ID = Interface.ServiceID ");
+ QList<QVariant> bindValues;
+
+ if (filter.serviceName().isEmpty() && filter.interfaceName().isEmpty()) {
+ //do nothing, (don't add any extra constraints to the query
+ } else {
+
+ if (!filter.serviceName().isEmpty()) {
+ whereComponent.append(QLatin1String("AND Service.Name = ?")).append(QLatin1String(" COLLATE NOCASE "));
+ bindValues.append(filter.serviceName());
+ }
+ if (!filter.interfaceName().isEmpty()) {
+ whereComponent.append(QLatin1String("AND Interface.Name = ?")).append(QLatin1String(" COLLATE NOCASE "));
+ bindValues.append(filter.interfaceName());
+ if (filter.majorVersion() >=0 && filter.minorVersion() >=0) {
+ if (filter.versionMatchRule() == QServiceFilter::ExactVersionMatch) {
+ whereComponent.append(QLatin1String("AND Interface.VerMaj = ?")).append(QLatin1String(" AND Interface.VerMin = ? "));
+ bindValues.append(QString::number(filter.majorVersion()));
+ bindValues.append(QString::number(filter.minorVersion()));
+ }
+ else if (filter.versionMatchRule() == QServiceFilter::MinimumVersionMatch) {
+ whereComponent.append(QLatin1String("AND ((Interface.VerMaj > ?"))
+ .append(QLatin1String(") OR Interface.VerMaj = ?")).append(QLatin1String(" AND Interface.VerMin >= ?")).append(QLatin1String(") "));
+ bindValues.append(QString::number(filter.majorVersion()));
+ bindValues.append(QString::number(filter.majorVersion()));
+ bindValues.append(QString::number(filter.minorVersion()));
+ }
+ }
+ }
+ }
+
+ if (!executeQuery(&query, selectComponent + fromComponent + whereComponent, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::getInterfaces():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ rollbackTransaction(&query);
+ return interfaces;
+ }
+
+ QServiceInterfaceDescriptor interface;
+ interface.d = new QServiceInterfaceDescriptorPrivate;
+ QStringList capabilities;
+ QString serviceID;
+ QString interfaceID;
+ const QSet<QString> filterCaps = filter.capabilities().toSet();
+ QSet<QString> difference;
+
+ while (query.next()){
+ difference.clear();
+ interface.d->customAttributes.clear();
+ interface.d->attributes.clear();
+ interface.d->interfaceName = query.value(EBindIndex).toString();
+ interface.d->serviceName = query.value(EBindIndex1).toString();
+ interface.d->major = query.value(EBindIndex2).toInt();
+ interface.d->minor = query.value(EBindIndex3).toInt();
+
+ QString location = query.value(EBindIndex4).toString();
+ if (location.startsWith(QLatin1String(SERVICE_IPC_PREFIX))) {
+ interface.d->attributes[QServiceInterfaceDescriptor::ServiceType] = QService::InterProcess;
+ interface.d->attributes[QServiceInterfaceDescriptor::Location]
+ = location.remove(0,QString(QLatin1String(SERVICE_IPC_PREFIX)).size());
+ } else {
+ interface.d->attributes[QServiceInterfaceDescriptor::ServiceType] = QService::Plugin;
+ interface.d->attributes[QServiceInterfaceDescriptor::Location] = location;
+ }
+
+ serviceID = query.value(EBindIndex5).toString();
+ if (!populateServiceProperties(&interface, serviceID)) {
+ //populateServiceProperties should already give a warning message
+ //and set the last error
+ interfaces.clear();
+ rollbackTransaction(&query);
+ return interfaces;
+ }
+
+ interfaceID = query.value(EBindIndex6).toString();
+ if (!populateInterfaceProperties(&interface, interfaceID)) {
+ //populateInterfaceProperties should already give a warning message
+ //and set the last error
+ interfaces.clear();
+ rollbackTransaction(&query);
+ return interfaces;
+ }
+
+ const QSet<QString> ifaceCaps = interface.d->attributes.value(QServiceInterfaceDescriptor::Capabilities).toStringList().toSet();
+ difference = ((filter.capabilityMatchRule() == QServiceFilter::MatchMinimum) ? (filterCaps-ifaceCaps) : (ifaceCaps-filterCaps));
+ if (!difference.isEmpty())
+ continue;
+
+ //only return those interfaces that comply with set custom filters
+ if (filter.customAttributes().size() > 0) {
+ QSet<QString> keyDiff = filter.customAttributes().toSet();
+ keyDiff.subtract(interface.d->customAttributes.uniqueKeys().toSet());
+ if (keyDiff.isEmpty()) { //target descriptor has same custom keys as filter
+ bool isMatch = true;
+ const QStringList keys = filter.customAttributes();
+ for (int i = 0; i<keys.count(); i++) {
+ if (interface.d->customAttributes.value(keys[i]) !=
+ filter.customAttribute(keys[i])) {
+ isMatch = false;
+ break;
+ }
+ }
+ if (isMatch)
+ interfaces.append(interface);
+ }
+ } else { //no custom keys -> SQL statement ensures proper selection already
+ interfaces.append(interface);
+ }
+ }
+
+ rollbackTransaction(&query);//read-only operation so just rollback
+ m_lastError.setError(DBError::NoError);
+ return interfaces;
+}
+
+/*
+ Obtains a QServiceInterfaceDescriptor that
+ corresponds to a given \a interfaceID
+
+ May set last error to one of the following error codes:
+ DBError::NoError
+ DBError::NotFound
+ DBError::SqlError
+ DBError::DatabaseNotOpen
+ DBError::InvalidDatabaseConnection
+ DBError::NoWritePermissions
+ DBError::InvalidDatabaseFile
+*/
+QServiceInterfaceDescriptor ServiceDatabase::getInterface(const QString &interfaceID)
+{
+ QServiceInterfaceDescriptor interface;
+ if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::getInterface():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return interface;
+ }
+
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+ QSqlQuery query(database);
+
+ if (!beginTransaction(&query, Read)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::getInterface():-"
+ << "Unable to begin transaction. "
+ << "Reason:" << qPrintable(m_lastError.text());
+#endif
+ return interface;
+ }
+
+ QString selectComponent = QLatin1String("SELECT Interface.Name, "
+ "Service.Name, Interface.VerMaj, "
+ "Interface.VerMin, "
+ "Service.Location, "
+ "Service.ID ");
+ QString fromComponent = QLatin1String("FROM Interface, Service ");
+ QString whereComponent = QLatin1String("WHERE Service.ID = Interface.ServiceID "
+ "AND Interface.ID = ? ");
+ QList<QVariant> bindValues;
+ bindValues.append(interfaceID);
+
+ if (!executeQuery(&query, selectComponent + fromComponent + whereComponent, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::getInterfaces():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return interface;
+ }
+
+ if (!query.next()) {
+ rollbackTransaction(&query);
+ QString errorText(QLatin1String("Interface implementation not found for Interface ID: %1"));
+ m_lastError.setError(DBError::NotFound, errorText.arg(interfaceID));
+ return interface;
+ }
+
+ interface.d = new QServiceInterfaceDescriptorPrivate;
+ interface.d->interfaceName =query.value(EBindIndex).toString();
+ interface.d->serviceName = query.value(EBindIndex1).toString();
+ interface.d->major = query.value(EBindIndex2).toInt();
+ interface.d->minor = query.value(EBindIndex3).toInt();
+
+ QString location = query.value(EBindIndex4).toString();
+ if (location.startsWith(QLatin1String(SERVICE_IPC_PREFIX))) {
+ interface.d->attributes[QServiceInterfaceDescriptor::ServiceType] = QService::InterProcess;
+ interface.d->attributes[QServiceInterfaceDescriptor::Location]
+ = location.remove(0,QString(QLatin1String(SERVICE_IPC_PREFIX)).size());
+ } else {
+ interface.d->attributes[QServiceInterfaceDescriptor::ServiceType] = QService::Plugin;
+ interface.d->attributes[QServiceInterfaceDescriptor::Location] = location;
+ }
+
+ QString serviceID = query.value(EBindIndex5).toString();
+ if (!populateServiceProperties(&interface, serviceID)) {
+ //populateServiceProperties should already give a warning message
+ //and set the last error
+ rollbackTransaction(&query);
+ return QServiceInterfaceDescriptor();
+ }
+
+ if (!populateInterfaceProperties(&interface, interfaceID)) {
+ //populateInterfaceProperties should already give a warning message
+ //and set the last error
+ rollbackTransaction(&query);
+ return QServiceInterfaceDescriptor();
+ }
+
+ rollbackTransaction(&query);//read only operation so just rollback
+ m_lastError.setError(DBError::NoError);
+ return interface;
+}
+
+/*
+ Obtains a list of services names. If \a interfaceName is empty,
+ then all service names are returned. If \a interfaceName specifies
+ an interface then the names of all services implementing that interface
+ are returned
+
+ May set last error to one of the following error codes:
+ DBError::NoError
+ DBError::SqlError
+ DBError::DatabaseNotOpen
+ DBError::InvalidDatabaseConnection
+ DBError::NoWritePermissions
+ DBError::InvalidDatabaseFile
+
+ Aside: There is only one query which implicitly gets
+ wrapped in it's own transaction.
+*/
+QStringList ServiceDatabase::getServiceNames(const QString &interfaceName)
+{
+ QStringList services;
+ if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::getServiceNames():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return services;
+ }
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+ QSqlQuery query(database);
+ QString selectComponent(QLatin1String("SELECT DISTINCT Service.Name COLLATE NOCASE "));
+ QString fromComponent;
+ QString whereComponent;
+ QList<QVariant> bindValues;
+ if (interfaceName.isEmpty()) {
+ fromComponent = QLatin1String("FROM Service ");
+ } else {
+ fromComponent = QLatin1String("FROM Interface,Service ");
+ whereComponent = QLatin1String("WHERE Service.ID = Interface.ServiceID AND Interface.Name = ? COLLATE NOCASE ");
+ bindValues.append(interfaceName);
+ }
+
+ if (!executeQuery(&query, selectComponent + fromComponent + whereComponent, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::getServiceNames():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return services;
+ }
+
+ while ( query.next()) {
+ services.append(query.value(EBindIndex).toString());
+ }
+ query.finish();
+ query.clear();
+ m_lastError.setError(DBError::NoError);
+ return services;
+}
+
+/*
+ Returns a descriptor for the default interface implementation of
+ \a interfaceName.
+
+ For user scope databases only, \a defaultInterfaceID is set if the default
+ in the user scope database refers to a interface implementation in the
+ system scope database. In this case the descriptor will be invalid and
+ the \a defaultInterfaceID must be used to query the system scope database,
+ The last error set to DBError::ExternalIfaceIDFound
+
+ If this function is called within a transaction, \a inTransaction
+ must be set to true. If \a inTransaction is false, this fuction
+ will begin and end its own transaction.
+
+ The last error may be set to one of the following error codes:
+ DBError::NoError
+ DBError::ExternalIfaceIDFound
+ DBError::SqlError
+ DBError::DatabaseNotOpen
+ DBError::InvalidDatabaseConnection
+ DBError::NoWritePermissions
+ DBError::InvalidDatabaseFile
+*/
+QServiceInterfaceDescriptor ServiceDatabase::interfaceDefault(const QString &interfaceName, QString *defaultInterfaceID,
+ bool inTransaction)
+{
+ QServiceInterfaceDescriptor interface;
+ if (!checkConnection())
+ {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::interfaceDefault():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return interface;
+ }
+
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+ QSqlQuery query(database);
+
+ if (!inTransaction && !beginTransaction(&query, Read)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::interfaceDefault(QString, QString):-"
+ << "Unable to begin transaction. "
+ << "Reason:" << qPrintable(m_lastError.text());
+#endif
+ return interface;
+ }
+
+ QString statement(QLatin1String("SELECT InterfaceID FROM Defaults WHERE InterfaceName = ? COLLATE NOCASE"));
+ QList<QVariant> bindValues;
+ bindValues.append(interfaceName);
+ if (!executeQuery(&query, statement, bindValues)) {
+ if (!inTransaction)
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::interfaceDefault():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return interface;
+ }
+
+ QString interfaceID;
+ if (!query.next())
+ {
+ if (!inTransaction)
+ rollbackTransaction(&query);
+ QString errorText(QLatin1String("No default service found for interface: \"%1\""));
+ m_lastError.setError(DBError::NotFound, errorText.arg(interfaceName));
+ return interface;
+ }
+ else
+ interfaceID = query.value(EBindIndex).toString();
+ Q_ASSERT(!interfaceID.isEmpty());
+
+ statement = QLatin1String("SELECT Interface.Name, "
+ "Service.Name, Interface.VerMaj, "
+ "Interface.VerMin, "
+ "Service.Location, "
+ "Service.ID "
+ "FROM Service, Interface "
+ "WHERE Service.ID = Interface.ServiceID AND Interface.ID = ?");
+ bindValues.clear();
+ bindValues.append(interfaceID);
+ if (!executeQuery(&query, statement, bindValues))
+ {
+ if (!inTransaction)
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::interfaceDefault():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return interface;
+ }
+
+ if (!query.next()) {
+ if (!inTransaction)
+ rollbackTransaction(&query);
+ if (defaultInterfaceID != NULL )
+ *defaultInterfaceID = interfaceID;
+ m_lastError.setError(DBError::ExternalIfaceIDFound);
+ return interface;
+ }
+
+ interface.d = new QServiceInterfaceDescriptorPrivate;
+ interface.d->interfaceName =query.value(EBindIndex).toString();
+ interface.d->serviceName = query.value(EBindIndex1).toString();
+ interface.d->major = query.value(EBindIndex2).toInt();
+ interface.d->minor = query.value(EBindIndex3).toInt();
+
+ QString location = query.value(EBindIndex4).toString();
+ if (location.startsWith(QLatin1String(SERVICE_IPC_PREFIX))) {
+ interface.d->attributes[QServiceInterfaceDescriptor::ServiceType] = QService::InterProcess;
+ interface.d->attributes[QServiceInterfaceDescriptor::Location]
+ = location.remove(0,QString(QLatin1String(SERVICE_IPC_PREFIX)).size());
+ } else {
+ interface.d->attributes[QServiceInterfaceDescriptor::ServiceType] = QService::Plugin;
+ interface.d->attributes[QServiceInterfaceDescriptor::Location] = location;
+ }
+
+ QString serviceID = query.value(EBindIndex5).toString();
+ if (!populateServiceProperties(&interface, serviceID)) {
+ //populateServiceProperties should already give a warning
+ //and set the last error
+ if (!inTransaction)
+ rollbackTransaction(&query);
+ return QServiceInterfaceDescriptor();
+ }
+
+ if (!populateInterfaceProperties(&interface, interfaceID)) {
+ //populateInterfaceProperties should already give a warning
+ //and set the last error
+ if (!inTransaction)
+ rollbackTransaction(&query);
+ return QServiceInterfaceDescriptor();
+ }
+
+ if (!inTransaction)
+ rollbackTransaction(&query); //Read only operation so just rollback
+ m_lastError.setError(DBError::NoError);
+ return interface;
+}
+
+/*
+ Sets a particular service's \a interface implementation as a the default
+ implementation to look up when using the interface's name in
+ interfaceDefault().
+
+ For a user scope database an \a externalInterfaceID can be provided
+ so that the Defaults table will contain a "link" to an interface
+ implmentation provided in the system scope database.
+
+ May set the last error to one of the following error codes:
+ DBError::NoError
+ DBerror::NotFound
+ DBError::SqlError
+ DBError::DatabaseNotOpen
+ DBError::InvalidDatabaseConnection
+ DBError::NoWritePermissions
+ DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::setInterfaceDefault(const QServiceInterfaceDescriptor &interface, const QString &externalInterfaceID)
+{
+ if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+ QSqlQuery query(database);
+
+ //Begin Transaction
+ if (!beginTransaction(&query, Write)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+ << "Problem: Unable to begin transaction."
+ << "Reason:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QString statement;
+ QList<QVariant> bindValues;
+ QString interfaceID = externalInterfaceID;
+ if (interfaceID.isEmpty()) {
+ statement = QLatin1String("SELECT Interface.ID from Interface, Service "
+ "WHERE Service.ID = Interface.ServiceID "
+ "AND Service.Name = ? COLLATE NOCASE "
+ "AND Interface.Name = ? COLLATE NOCASE "
+ "AND Interface.VerMaj = ? "
+ "AND Interface.VerMin = ? ");
+ bindValues.append(interface.serviceName());
+ bindValues.append(interface.interfaceName());
+ bindValues.append(interface.majorVersion());
+ bindValues.append(interface.minorVersion());
+
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ if (!query.next()) {
+ QString errorText;
+ errorText = QLatin1String("No implementation for interface: %1, Version: %2.%3 found "
+ "for service: %4");
+ m_lastError.setNotFoundError(errorText.arg(interface.interfaceName())
+ .arg(interface.majorVersion())
+ .arg(interface.minorVersion())
+ .arg(interface.serviceName()));
+
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatbase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+ << "Problem: Unable to set default service. "
+ << "Reason:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ interfaceID = query.value(EBindIndex).toString();
+ Q_ASSERT(!interfaceID.isEmpty());
+ }
+
+ statement = QLatin1String("SELECT InterfaceName FROM Defaults WHERE InterfaceName = ? COLLATE NOCASE");
+ bindValues.clear();
+ bindValues.append(interface.interfaceName());
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ if (query.next()) {
+ statement = QLatin1String("UPDATE Defaults "
+ "SET InterfaceID = ? "
+ "WHERE InterfaceName = ? COLLATE NOCASE");
+ bindValues.clear();
+ bindValues.append(interfaceID);
+ bindValues.append(interface.interfaceName());
+
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ } else {
+ statement = QLatin1String("INSERT INTO Defaults(InterfaceName,InterfaceID) VALUES(?,?)");
+ bindValues.clear();
+ bindValues.append(interface.interfaceName());
+ bindValues.append(interfaceID);
+
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ }
+
+ //End Transaction
+ if (!commitTransaction(&query)) {
+ rollbackTransaction(&query);
+ return false;
+ }
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+/*
+ Removes the service with name \a serviceName.
+ If the service provides a default interface implementation, then
+ another service implementing the highest interface implementation
+ version becomes the new default(if any). If more than one service
+ provides same the highest version number, an arbitrary choice is made
+ between them.
+
+ May set the last error to the folowing error codes:
+ DBError::NoError
+ DBError::NotFound
+ DBError::SqlError
+ DBError::DatabaseNotOpen
+ DBError::InvalidDatabaseConnection
+ DBError::NoWritePermissions
+ DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::unregisterService(const QString &serviceName, const QString &securityToken)
+{
+#ifndef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+ Q_UNUSED(securityToken);
+#else
+ if (securityToken.isEmpty()) {
+ QString errorText(QLatin1String("Access denied, no security token provided (for unregistering service: \"%1\")"));
+ m_lastError.setError(DBError::NoWritePermissions, errorText.arg(serviceName));
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << "Problem: Unable to unregister service. "
+ << "Reason:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+#endif
+
+
+ if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+ QSqlQuery query(database);
+
+ if (!beginTransaction(&query, Write)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << "Problem: Unable to begin transaction. "
+ << "Reason:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QString statement(QLatin1String("SELECT Service.ID from Service WHERE Service.Name = ? COLLATE NOCASE"));
+ QList<QVariant> bindValues;
+ bindValues.append(serviceName);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QStringList serviceIDs;
+ while (query.next()) {
+ serviceIDs << query.value(EBindIndex).toString();
+ }
+
+#ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+ // Only the application that registered the service is allowed to unregister that
+ // service. Fetch a security ID of a service (with given name) and verify that it matches
+ // with current apps security id. Only one application is allowed to register services with
+ // same name, hence a distinct (just any of the) security token will do because they are identical.
+ if (!serviceIDs.isEmpty()) {
+ statement = QLatin1String("SELECT DISTINCT Value FROM ServiceProperty WHERE ServiceID = ? AND Key = ?");
+ bindValues.clear();
+ bindValues.append(serviceIDs.first());
+ bindValues.append(SECURITY_TOKEN_KEY);
+
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ QString existingSecurityToken;
+ if (query.next()) {
+ existingSecurityToken = query.value(EBindIndex).toString();
+ }
+ if (existingSecurityToken != securityToken) {
+ QString errorText(QLatin1String("Access denied: \"%1\""));
+ m_lastError.setError(DBError::NoWritePermissions, errorText.arg(serviceName));
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << "Problem: Unable to unregister service"
+ << "Reason:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ }
+#endif // QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+
+ statement = QLatin1String("SELECT Interface.ID from Interface, Service "
+ "WHERE Interface.ServiceID = Service.ID "
+ "AND Service.Name =? COLLATE NOCASE");
+ bindValues.clear();
+ bindValues.append(serviceName);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QStringList interfaceIDs;
+ while (query.next()) {
+ interfaceIDs << query.value(EBindIndex).toString();
+ }
+
+ if (serviceIDs.count() == 0) {
+ QString errorText(QLatin1String("Service not found: \"%1\""));
+ m_lastError.setError(DBError::NotFound, errorText.arg(serviceName));
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << "Problem: Unable to unregister service"
+ << "Reason:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ statement = QLatin1String("SELECT Defaults.InterfaceName "
+ "FROM Defaults, Interface, Service "
+ "WHERE Defaults.InterfaceID = Interface.ID "
+ "AND Interface.ServiceID = Service.ID "
+ "AND Service.Name = ? COLLATE NOCASE");
+ bindValues.clear();
+ bindValues.append(serviceName);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase:unregisterService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QStringList serviceDefaultInterfaces;
+ while (query.next()) {
+ serviceDefaultInterfaces << query.value(EBindIndex).toString();
+ }
+
+
+ statement = QLatin1String("DELETE FROM Service WHERE Service.Name = ? COLLATE NOCASE");
+ bindValues.clear();
+ bindValues.append(serviceName);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ statement = QLatin1String("DELETE FROM Interface WHERE Interface.ServiceID = ?");
+ foreach (const QString &serviceID, serviceIDs) {
+ bindValues.clear();
+ bindValues.append(serviceID);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ }
+
+ statement = QLatin1String("DELETE FROM ServiceProperty WHERE ServiceID = ?");
+
+ foreach (const QString &serviceID, serviceIDs) {
+ bindValues.clear();
+ bindValues.append(serviceID);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ }
+
+ statement = QLatin1String("DELETE FROM InterfaceProperty WHERE InterfaceID = ?");
+ foreach (const QString &interfaceID, interfaceIDs) {
+ bindValues.clear();
+ bindValues.append(interfaceID);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ }
+
+ foreach (const QString &interfaceName, serviceDefaultInterfaces) {
+ statement = QLatin1String("SELECT ID FROM Interface WHERE Interface.Name = ? COLLATE NOCASE "
+ "ORDER BY Interface.VerMaj DESC, Interface.VerMin DESC");
+ bindValues.clear();
+ bindValues.append(interfaceName);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ if (query.next()) {
+ QString newDefaultID = query.value(EBindIndex).toString();
+ statement = QLatin1String("UPDATE Defaults SET InterfaceID = ? WHERE InterfaceName = ? COLLATE NOCASE ");
+ bindValues.clear();
+ bindValues.append(newDefaultID);
+ bindValues.append(interfaceName);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ } else {
+ statement = QLatin1String("DELETE FROM Defaults WHERE InterfaceName = ? COLLATE NOCASE ");
+ bindValues.clear();
+ bindValues.append(interfaceName);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ }
+ }
+
+ //databaseCommit
+ if (!commitTransaction(&query)) {
+ rollbackTransaction(&query);
+ return false;
+ }
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+/*
+ Registers the service initialization into the database.
+*/
+bool ServiceDatabase::serviceInitialized(const QString &serviceName, const QString &securityToken)
+{
+#ifndef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+ Q_UNUSED(securityToken);
+#endif
+
+ if (!checkConnection()) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+ QSqlQuery query(database);
+
+ if (!beginTransaction(&query, Write)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::serviceInitialized():-"
+ << "Problem: Unable to begin transaction"
+ << "\nReason:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QString statement(QLatin1String("SELECT Service.ID from Service WHERE Service.Name = ? COLLATE NOCASE"));
+ QList<QVariant> bindValues;
+ bindValues.append(serviceName);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::serviceInitialized():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QStringList serviceIDs;
+ while(query.next()) {
+ serviceIDs << query.value(EBindIndex).toString();
+ }
+
+
+#ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
+ statement = QLatin1String("SELECT Value FROM ServiceProperty WHERE ServiceID = ? AND Key = ?");
+ bindValues.clear();
+ bindValues.append(serviceName);
+ bindValues.append(SECURITY_TOKEN_KEY);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::unregisterService():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QStringList securityTokens;
+ while (query.next()) {
+ securityTokens << query.value(EBindIndex).toString();
+ }
+
+ if (!securityTokens.isEmpty() && (securityTokens.first() != securityToken)) {
+ QString errorText(QLatin1String("Access denied: \"%1\""));
+ m_lastError.setError(DBError::NoWritePermissions, errorText.arg(serviceName));
+ rollbackTransaction(&query);
+ #ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::serviceInitialized():-"
+ << "Problem: Unable to update service initialization"
+ << "\nReason:" << qPrintable(m_lastError.text());
+ #endif
+ }
+#endif
+
+ statement = QLatin1String("DELETE FROM ServiceProperty WHERE ServiceID = ? AND Key = ?");
+ foreach (const QString &serviceID, serviceIDs) {
+ bindValues.clear();
+ bindValues.append(serviceID);
+ bindValues.append(QLatin1String(SERVICE_INITIALIZED_KEY));
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::serviceInitialized():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ }
+
+ //databaseCommit
+ if (!commitTransaction(&query)) {
+ rollbackTransaction(&query);
+ return false;
+ }
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+/*
+ Closes the database
+
+ May set the following error codes:
+ DBError::NoError
+ DBError::InvalidDatabaseConnection
+*/
+bool ServiceDatabase::close()
+{
+ if (m_isDatabaseOpen) {
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName, false);
+ if (database.isValid()) {
+ if (database.isOpen()) {
+ database.close();
+ m_isDatabaseOpen = false;
+ return true;
+ }
+ } else {
+ m_lastError.setError(DBError::InvalidDatabaseConnection);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::close():-"
+ << "Problem: " << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ }
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+/*
+ Sets the path of the service database to \a databasePath
+*/
+void ServiceDatabase::setDatabasePath(const QString &databasePath)
+{
+ m_databasePath = QDir::toNativeSeparators(databasePath);
+}
+
+/*
+ Returns the path of the service database
+*/
+QString ServiceDatabase::databasePath() const
+{
+ QString path;
+ if (m_databasePath.isEmpty()) {
+#ifdef Q_OS_SYMBIAN
+ QString qtVersion(qVersion());
+ qtVersion = qtVersion.left(qtVersion.size() -2); //strip off patch version
+ path = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/QtServiceFramework_" +
+ qtVersion + "_system" + QLatin1String(".db"));
+#else
+ QSettings settings(QSettings::SystemScope, QLatin1String("Nokia"), QLatin1String("Services"));
+ path = settings.value(QLatin1String("ServicesDB/Path")).toString();
+ if (path.isEmpty()) {
+ path = QDir::currentPath();
+ if (path.lastIndexOf(QLatin1String(RESOLVERDATABASE_PATH_SEPARATOR)) != path.length() -1) {
+ path.append(QLatin1String(RESOLVERDATABASE_PATH_SEPARATOR));
+ }
+ path.append(QLatin1String(RESOLVERDATABASE));
+ }
+ path = QDir::toNativeSeparators(path);
+#endif
+ } else {
+ path = m_databasePath;
+ }
+
+ return path;
+}
+
+/*
+ Helper method that creates the database tables: Service, Interface,
+ Defaults, ServiceProperty and InterfaceProperty
+
+ May set the last error to one of the following error codes:
+ DBError::NoError
+ DBError::SqlError
+ DBError::NoWritePermissions
+ DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::createTables()
+{
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+ QSqlQuery query(database);
+
+ //Begin Transaction
+ if (!beginTransaction(&query, Write)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::createTables():-"
+ << "Unable to begin transaction. "
+ << "Reason:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QString statement(QLatin1String("CREATE TABLE Service("
+ "ID TEXT NOT NULL PRIMARY KEY UNIQUE,"
+ "Name TEXT NOT NULL, "
+ "Location TEXT NOT NULL)"));
+ if (!executeQuery(&query, statement)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::createTables():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ statement = QLatin1String("CREATE TABLE Interface("
+ "ID TEXT NOT NULL PRIMARY KEY UNIQUE,"
+ "ServiceID TEXT NOT NULL, "
+ "Name TEXT NOT NULL, "
+ "VerMaj INTEGER NOT NULL, "
+ "VerMin INTEGER NOT NULL)");
+ if (!executeQuery(&query, statement)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::createTables():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ statement = QLatin1String("CREATE TABLE Defaults("
+ "InterfaceName TEXT PRIMARY KEY UNIQUE NOT NULL,"
+ "InterfaceID TEXT NOT NULL)");
+ if (!executeQuery(&query, statement)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::createTables():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ statement = QLatin1String("CREATE TABLE ServiceProperty("
+ "ServiceID TEXT NOT NULL,"
+ "Key TEXT NOT NULL,"
+ "Value TEXT NOT NULL)");
+ if (!executeQuery(&query, statement)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::createTables():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ statement = QLatin1String("CREATE TABLE InterfaceProperty("
+ "InterfaceID TEXT NOT NULL,"
+ "Key TEXT NOT NULL,"
+ "Value TEXT NOT NULL)");
+
+ if (!executeQuery(&query, statement)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::createTables():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ if (!commitTransaction(&query)) {
+ rollbackTransaction(&query);
+ return false;
+ }
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+/*!
+ Helper method that checks if the all expected tables exist in the database
+ Returns true if they all exist and false if any of them don't
+*/
+bool ServiceDatabase::checkTables()
+{
+ bool bTables(false);
+ QStringList tables = QSqlDatabase::database(m_connectionName).tables();
+ if (tables.contains(QLatin1String(SERVICE_TABLE))
+ && tables.contains(QLatin1String(INTERFACE_TABLE))
+ && tables.contains(QLatin1String(DEFAULTS_TABLE))
+ && tables.contains(QLatin1String(SERVICE_PROPERTY_TABLE))
+ && tables.contains(QLatin1String(INTERFACE_PROPERTY_TABLE))){
+ bTables = true;
+ }
+ return bTables;
+}
+
+/*
+ This function should only ever be used on a user scope database
+ It removes an entry from the Defaults table where the default
+ refers to an interface implementation in the system scope database.
+ The particular default that is removed is specified by
+ \a interfaceID.
+
+ May set the last error to one of the following error codes:
+ DBError::NoError
+ DBError::IfaceIDNotExternal
+ DBError::SqlError
+ DBError::NoWritePermissions
+ DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::removeExternalDefaultServiceInterface(const QString &interfaceID)
+{
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+ QSqlQuery query(database);
+
+ //begin transaction
+ if (!beginTransaction(&query, Write)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::removeExternalDefaultServiceInterface():-"
+ << "Problem: Unable to begin transaction. "
+ << "Reason:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ QString statement(QLatin1String("SELECT Name FROM Interface WHERE Interface.ID = ?"));
+ QList<QVariant> bindValues;
+ bindValues.append(interfaceID);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::removeDefaultServiceInterface():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ if (query.next()) {
+ QString interfaceName = query.value(EBindIndex).toString();
+ QString errorText(QLatin1String("Local interface implementation exists for interface \"%1\" "
+ "with interfaceID: \"%2\""));
+ m_lastError.setError(DBError::IfaceIDNotExternal,
+ errorText.arg(interfaceName).arg(interfaceID));
+ rollbackTransaction(&query);
+ return false;
+ }
+
+ statement = QLatin1String("DELETE FROM Defaults WHERE InterfaceID = ? COLLATE NOCASE");
+ bindValues.clear();
+ bindValues.append(interfaceID);
+ if (!executeQuery(&query, statement, bindValues)) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::removeDefaultServiceInterface():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ //end transaction
+ if (!commitTransaction(&query)){
+ rollbackTransaction(&query);
+ return false;
+ }
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+/*
+ Removes all tables from the database
+
+ In future this function may be deprecated or removed.
+
+ May set the last error to one of the following error codes:
+ DBError::NoError
+ DBError::SqlError
+ DBError::NoWritePermissions
+ DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::dropTables()
+{
+ //Execute transaction for deleting the database tables
+ QSqlDatabase database = QSqlDatabase::database(m_connectionName);
+ QSqlQuery query(database);
+ QStringList expectedTables;
+ expectedTables << QLatin1String(SERVICE_TABLE)
+ << QLatin1String(INTERFACE_TABLE)
+ << QLatin1String(DEFAULTS_TABLE)
+ << QLatin1String(SERVICE_PROPERTY_TABLE)
+ << QLatin1String(INTERFACE_PROPERTY_TABLE);
+
+ if (database.tables().count() > 0) {
+ if (!beginTransaction(&query, Write)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::dropTables():-"
+ << "Unable to begin transaction. "
+ << "Reason:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ QStringList actualTables = database.tables();
+
+ foreach (const QString expectedTable, expectedTables) {
+ if ((actualTables.contains(expectedTable))
+ && (!executeQuery(&query, QLatin1String("DROP TABLE ") + expectedTable))) {
+ rollbackTransaction(&query);
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::dropTables():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ }
+ if (!commitTransaction(&query)) {
+ rollbackTransaction(&query);
+ return false;
+ }
+ }
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+/*
+ Checks if the database is open
+*/
+bool ServiceDatabase::isOpen() const
+{
+ return m_isDatabaseOpen;
+}
+
+/*
+ Checks the database connection.
+
+ May set the last error to one of the following error codes:
+ DBError::DatabaseNotOpen
+ DBError::InvalidDatabaseConnection
+*/
+bool ServiceDatabase::checkConnection()
+{
+ if (!m_isDatabaseOpen)
+ {
+ m_lastError.setError(DBError::DatabaseNotOpen);
+ return false;
+ }
+
+ if (!QSqlDatabase::database(m_connectionName).isValid())
+ {
+ m_lastError.setError(DBError::InvalidDatabaseConnection);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ Begins a transcaction based on the \a type which can be Read or Write.
+
+ May set the last error to one of the following error codes:
+ DBError::NoError
+ DBError::SqlError
+ DBError::NoWritePermissions
+ DBError::InvalidDatabaseFile
+*/
+bool ServiceDatabase::beginTransaction(QSqlQuery *query, TransactionType type)
+{
+ bool success;
+ if (type == Read)
+ success = query->exec(QLatin1String("BEGIN"));
+ else
+ success = query->exec(QLatin1String("BEGIN IMMEDIATE"));
+
+ if (!success) {
+ int result = query->lastError().number();
+ if (result == 26 || result == 11) {//SQLITE_NOTADB || SQLITE_CORRUPT
+ qWarning() << "Service Framework:- Database file is corrupt or invalid:" << databasePath();
+ m_lastError.setError(DBError::InvalidDatabaseFile, query->lastError().text());
+ }
+ else if (result == 8) { //SQLITE_READONLY
+ qWarning() << "Service Framework:- Insufficient permissions to write to database:" << databasePath();
+ m_lastError.setError(DBError::NoWritePermissions, query->lastError().text());
+ }
+ else
+ m_lastError.setError(DBError::SqlError, query->lastError().text());
+ return false;
+ }
+
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+/*
+ Commits a transaction
+
+ May set the last error to one of the following error codes:
+ DBError::NoError
+ DBError::SqlError
+*/
+bool ServiceDatabase::commitTransaction(QSqlQuery *query)
+{
+ Q_ASSERT(query != NULL);
+ query->finish();
+ query->clear();
+ if (!query->exec(QLatin1String("COMMIT"))) {
+ m_lastError.setError(DBError::SqlError, query->lastError().text());
+ return false;
+ }
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+/*
+ Rolls back a transaction
+
+ May set the last error to one of the following error codes:
+ DBError::NoError
+ DBError::SqlError
+*/
+bool ServiceDatabase::rollbackTransaction(QSqlQuery *query)
+{
+ Q_ASSERT(query !=NULL);
+ query->finish();
+ query->clear();
+
+ if (!query->exec(QLatin1String("ROLLBACK"))) {
+ m_lastError.setError(DBError::SqlError, query->lastError().text());
+ return false;
+ }
+ return true;
+}
+
+/*
+ Helper function that populates a service \a interface descriptor
+ with interface related attributes corresponding to the interface
+ represented by \a interfaceID
+
+ It is already assumed that a transaction has been started by the time
+ this function is called. This function will not rollback/commit the
+ transaction.
+
+ May set the last error to one of the following error codes:
+ DBError::NoError
+ DBError::SqlError
+*/
+bool ServiceDatabase::populateInterfaceProperties(QServiceInterfaceDescriptor *interface, const QString &interfaceID)
+{
+ QSqlQuery query(QSqlDatabase::database(m_connectionName));
+ QString statement(QLatin1String("SELECT Key, Value FROM InterfaceProperty WHERE InterfaceID = ?"));
+ QList<QVariant> bindValues;
+ bindValues.append(interfaceID);
+ if (!executeQuery(&query, statement, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::populateInterfaceProperties():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ bool isFound = false;
+ QString attribute;
+ while (query.next()) {
+ isFound = true;
+ attribute = query.value(EBindIndex).toString();
+ if (attribute == QLatin1String(INTERFACE_CAPABILITY_KEY)) {
+ const QStringList capabilities = query.value(EBindIndex1).toString().split(QLatin1String(","));
+ if (capabilities.count() == 1 && capabilities[0].isEmpty()) {
+ interface->d->attributes[QServiceInterfaceDescriptor::Capabilities]
+ = QStringList();
+ } else {
+ interface->d->attributes[QServiceInterfaceDescriptor::Capabilities]
+ = capabilities;
+ }
+ } else if (attribute == QLatin1String(INTERFACE_DESCRIPTION_KEY)) {
+ interface->d->attributes[QServiceInterfaceDescriptor::InterfaceDescription]
+ = query.value(EBindIndex1).toString();
+ } else if (attribute.startsWith(QLatin1String("c_"))) {
+ interface->d->customAttributes[attribute.mid(2)]
+ = query.value(EBindIndex1).toString();
+ }
+ }
+
+ if (!isFound) {
+ QString errorText(QLatin1String("Database integrity corrupted, Properties for InterfaceID: %1 does not exist in the InterfaceProperty table for interface \"%2\""));
+ m_lastError.setError(DBError::SqlError, errorText.arg(interfaceID).arg(interface->interfaceName()));
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::populateInterfaceProperties():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+/*
+ Helper function that populates a service \a interface descriptor
+ with service related attributes corresponding to the service
+ represented by \a serviceID
+
+ It is already assumed that a transaction has been started by the time
+ this function is called. This function will not rollback/commit the
+ transaction.
+
+ May set the last error to one of the following error codes:
+ DBError::NoError
+ DBError::SqlError
+*/
+bool ServiceDatabase::populateServiceProperties(QServiceInterfaceDescriptor *interface, const QString &serviceID)
+{
+ QSqlQuery query(QSqlDatabase::database(m_connectionName));
+ QString statement(QLatin1String("SELECT Key, Value FROM ServiceProperty WHERE ServiceID = ?"));
+ QList<QVariant> bindValues;
+ bindValues.append(serviceID);
+ if (!executeQuery(&query, statement, bindValues)) {
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::populateServiceProperties():-"
+ << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+
+ bool isFound = false;
+ QString attribute;
+ while (query.next()) {
+ isFound = true;
+ attribute = query.value(EBindIndex).toString();
+ if (attribute == QLatin1String(SERVICE_DESCRIPTION_KEY)) {
+ interface->d->attributes[QServiceInterfaceDescriptor::ServiceDescription]
+ = query.value(EBindIndex1).toString();
+ }
+ // fetch initialized and put it as a custom attribute
+ if (attribute == QLatin1String(SERVICE_INITIALIZED_KEY)) {
+ interface->d->customAttributes[attribute] = query.value(EBindIndex1).toString();
+ }
+ }
+
+ if (!isFound) {
+ QString errorText(QLatin1String("Database integrity corrupted, Service Properties for ServiceID: \"%1\" does not exist in the ServiceProperty table for service \"%2\""));
+ m_lastError.setError(DBError::SqlError, errorText.arg(serviceID).arg(interface->serviceName()));
+#ifdef QT_SFW_SERVICEDATABASE_DEBUG
+ qWarning() << "ServiceDatabase::populateServiceProperties():-"
+ << "Problem:" << qPrintable(m_lastError.text());
+#endif
+ return false;
+ }
+ m_lastError.setError(DBError::NoError);
+ return true;
+}
+
+#include "moc_servicedatabase_p.cpp"
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/servicedatabase_p.h b/src/serviceframework/servicedatabase_p.h
new file mode 100644
index 00000000..ff8fac30
--- /dev/null
+++ b/src/serviceframework/servicedatabase_p.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSERVICEDATABASE_H_
+#define QSERVICEDATABASE_H_
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qserviceframeworkglobal.h"
+#include <QtSql>
+#include <QList>
+#include "servicemetadata_p.h"
+#include "qservicefilter.h"
+#include "dberror_p.h"
+
+
+QT_BEGIN_HEADER
+QTM_BEGIN_NAMESPACE
+
+class QServiceInterfaceDescriptor;
+
+class Q_AUTOTEST_EXPORT ServiceDatabase : public QObject
+{
+ Q_OBJECT
+
+ public:
+ ServiceDatabase(void);
+
+ virtual ~ServiceDatabase();
+
+ bool open();
+ bool close();
+
+ bool isOpen() const;
+ void setDatabasePath(const QString &databasePath);
+ QString databasePath() const;
+
+ bool registerService(const ServiceMetaDataResults &service, const QString &securityToken = QString());
+ bool unregisterService(const QString &serviceName, const QString &securityToken = QString());
+ bool serviceInitialized(const QString &serviceName, const QString &securityToken = QString());
+
+ QList<QServiceInterfaceDescriptor> getInterfaces(const QServiceFilter &filter);
+ QServiceInterfaceDescriptor getInterface(const QString &interfaceID);
+ QString getInterfaceID(const QServiceInterfaceDescriptor &interface);
+ QStringList getServiceNames(const QString &interfaceName);
+
+ QServiceInterfaceDescriptor interfaceDefault(const QString &interfaceName,
+ QString *interfaceID = 0, bool inTransaction = false);
+ bool setInterfaceDefault(const QServiceInterfaceDescriptor &interface,
+ const QString &externalInterfaceID = QString());
+ QList<QPair<QString,QString> > externalDefaultsInfo();
+ bool removeExternalDefaultServiceInterface(const QString &interfaceID);
+
+ DBError lastError() const { return m_lastError; }
+
+Q_SIGNALS:
+ void serviceAdded(const QString& serviceName);
+ void serviceRemoved(const QString& serviceName);
+
+#ifdef QTM_BUILD_UNITTESTS
+ public:
+#else
+ private:
+#endif
+ enum TransactionType{Read, Write};
+
+ bool createTables();
+ bool dropTables();
+ bool checkTables();
+
+ bool checkConnection();
+
+ bool executeQuery(QSqlQuery *query, const QString &statement, const QList<QVariant> &bindValues = QList<QVariant>());
+ QString getInterfaceID(QSqlQuery *query, const QServiceInterfaceDescriptor &interface);
+ bool insertInterfaceData(QSqlQuery *query, const QServiceInterfaceDescriptor &anInterface, const QString &serviceID);
+
+ bool beginTransaction(QSqlQuery *query, TransactionType);
+ bool commitTransaction(QSqlQuery *query);
+ bool rollbackTransaction(QSqlQuery *query);
+
+ bool populateInterfaceProperties(QServiceInterfaceDescriptor *descriptor, const QString &interfaceID);
+ bool populateServiceProperties(QServiceInterfaceDescriptor *descriptor, const QString &serviceID);
+
+ QString m_databasePath;
+ QString m_connectionName;
+ bool m_isDatabaseOpen;
+ bool m_inTransaction;
+ DBError m_lastError;
+};
+
+QTM_END_NAMESPACE
+QT_END_HEADER
+
+#endif /*QSERVICEDATABASE_H_*/
diff --git a/src/serviceframework/serviceframework.pro b/src/serviceframework/serviceframework.pro
new file mode 100644
index 00000000..22489b1a
--- /dev/null
+++ b/src/serviceframework/serviceframework.pro
@@ -0,0 +1,55 @@
+load(qt_module)
+load(qt_module_config)
+
+TARGET = QtServiceFramework
+QPRO_PWD = $PWD
+
+CONFIG += module
+MODULE_PRI = ../../modules/qt_servicefrramework.pri
+
+QT = core sql
+
+DEFINES += QT_BUILD_SFW_LIB QT_MAKEDLL
+
+include(ipc/ipc.pri)
+
+PUBLIC_HEADERS += qservice.h \
+ qservicemanager.h \
+ qserviceplugininterface.h \
+ qservicecontext.h \
+ qabstractsecuritysession.h \
+ qserviceinterfacedescriptor.h \
+ qservicefilter.h \
+ qremoteserviceregister.h
+PRIVATE_HEADERS += servicedatabase_p.h \
+ databasemanager_p.h \
+ servicemetadata_p.h \
+ qserviceinterfacedescriptor_p.h \
+ dberror_p.h
+SOURCES += servicemetadata.cpp \
+ qservicemanager.cpp \
+ qserviceplugininterface.cpp \
+ qservicecontext.cpp \
+ qabstractsecuritysession.cpp \
+ qserviceinterfacedescriptor.cpp \
+ qservicefilter.cpp \
+ dberror.cpp \
+ qremoteserviceregister.cpp
+symbian {
+ contains(S60_VERSION, 5.2)|contains(MOBILITY_SD_MCL_BUILD, yes){
+ DEFINES += SYMBIAN_EMULATOR_SUPPORTS_PERPROCESS_WSD
+ }
+ INCLUDEPATH += ./databasemanagerserver_symbian
+ PRIVATE_HEADERS += databasemanager_symbian_p.h
+ SOURCES += databasemanager_symbian.cpp
+ TARGET.CAPABILITY = ALL \
+ -TCB
+ TARGET.UID3 = 0x2002AC84
+ QtServiceFrameworkDeployment.sources = QtServiceFramework.dll \
+ qsfwdatabasemanagerserver.exe
+ QtServiceFrameworkDeployment.path = /sys/bin
+ DEPLOYMENT += QtServiceFrameworkDeployment
+} else:SOURCES += servicedatabase.cpp \
+ databasemanager.cpp
+
+HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS
diff --git a/src/serviceframework/servicemetadata.cpp b/src/serviceframework/servicemetadata.cpp
new file mode 100644
index 00000000..b0083e3a
--- /dev/null
+++ b/src/serviceframework/servicemetadata.cpp
@@ -0,0 +1,725 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "servicemetadata_p.h"
+#include <QFile>
+#include <QDebug>
+#include "qserviceinterfacedescriptor_p.h"
+
+//XML tags and attributes
+//General
+#define NAME_TAG "name"
+#define DESCRIPTION_TAG "description"
+#define SERVICEFW_TAG "SFW"
+#define XML_MAX "1.1"
+
+//Service related
+#define SERVICE_TAG "service"
+#define SERVICE_FILEPATH "filepath"
+#define SERVICE_IPCADDRESS "ipcaddress"
+
+//Interface related
+#define INTERFACE_TAG "interface"
+#define INTERFACE_VERSION "version"
+#define INTERFACE_CAPABILITY "capabilities"
+#define INTERFACE_CUSTOM_PROPERTY "customproperty"
+
+//Service type prefix
+#define SERVICE_IPC_PREFIX "_q_ipc_addr:"
+
+QTM_BEGIN_NAMESPACE
+
+#ifndef QT_NO_DATASTREAM
+QDataStream &operator<<(QDataStream &out, const ServiceMetaDataResults &r)
+{
+ out << r.type << r.name << r.location;
+ out << r.description << r.interfaces << r.latestInterfaces;
+
+ return out;
+}
+
+QDataStream &operator>>(QDataStream &in, ServiceMetaDataResults &r)
+{
+ in >> r.type >> r.name >> r.location;
+ in >> r.description >> r.interfaces >> r.latestInterfaces;
+
+ return in;
+}
+#endif
+
+/*
+ \class ServiceMetaData
+
+ \since 1.0
+
+ Utility class (used by service database) that offers support for
+ parsing metadata service xml registry file during service registration. \n
+
+ It uses QXMLStreamReader class for parsing. Supproted Operations are:
+ - Parse the service and interfaces defined in XML file
+ - name, version, capabilitiesList, description and filePath of service can be retrieved
+ - each interface can be retrieved
+*/
+
+/*
+ * Class constructor
+ *
+ * @param aXmlFilePath path to the xml file that describes the service.
+ */
+ServiceMetaData::ServiceMetaData(const QString &aXmlFilePath)
+{
+ xmlDevice = new QFile(aXmlFilePath);
+ ownsXmlDevice = true;
+ latestError = 0;
+}
+
+/*
+ * Class constructor
+ *
+ * @param device QIODevice that contains the XML data that describes the service.
+ */
+ServiceMetaData::ServiceMetaData(QIODevice *device)
+{
+ xmlDevice = device;
+ ownsXmlDevice = false;
+ latestError = 0;
+}
+
+/*
+ * Class destructor
+ *
+ */
+ServiceMetaData::~ServiceMetaData()
+{
+ if (ownsXmlDevice)
+ delete xmlDevice;
+}
+
+/*
+ Sets the device containing the XML data that describes the service to \a device.
+ */
+void ServiceMetaData::setDevice(QIODevice *device)
+{
+ clearMetadata();
+ xmlDevice = device;
+ ownsXmlDevice = false;
+}
+
+/*
+ Returns the device containing the XML data that describes the service.
+*/
+QIODevice *ServiceMetaData::device() const
+{
+ return xmlDevice;
+}
+
+/*
+ * Gets the service name
+ *
+ * @return service name or default value (empty string) if it is not available
+ */
+/*QString ServiceMetaData::name() const
+{
+ return serviceName;
+}*/
+
+/*
+ * Gets the path of the service implementation file
+ *
+ * @return service implementation filepath
+ */
+/*QString ServiceMetaData::location() const
+{
+ return serviceLocation;
+}*/
+
+/*
+ * Gets the service description
+ *
+ * @return service description or default value (empty string) if it is not available
+ */
+/*QString ServiceMetaData::description() const
+{
+ return serviceDescription;
+}*/
+
+/*
+ Returns the metadata of the interace at \a index; otherwise
+ returns 0.
+ */
+/*QList<QServiceInterfaceDescriptor> ServiceMetaData::getInterfaces() const
+{
+ return serviceInterfaces;
+} */
+
+/*!
+ \internal
+
+ Returns a streamable object containing the results of the parsing.
+*/
+ServiceMetaDataResults ServiceMetaData::parseResults() const
+{
+ ServiceMetaDataResults results;
+ results.type = serviceType;
+ results.location = serviceLocation;
+ results.name = serviceName;
+ results.description = serviceDescription;
+ results.interfaces = serviceInterfaces;
+ results.latestInterfaces = latestInterfaces();
+
+ return results;
+}
+
+/*
+ Parses the file and extracts the service metadata \n
+ Custom error codes: \n
+ SFW_ERROR_UNABLE_TO_OPEN_FILE in case can not open the XML file \n
+ SFW_ERROR_INVALID_XML_FILE in case service registry is not a valid XML file \n
+ SFW_ERROR_NO_SERVICE in case XML file has no service tag\n
+ @return true if the metadata was read properly, false if there is an error
+ */
+bool ServiceMetaData::extractMetadata()
+{
+ Q_ASSERT(checkVersion(QLatin1String(XML_MAX)));
+
+ latestError = 0;
+ clearMetadata();
+ QXmlStreamReader xmlReader;
+ bool parseError = false;
+ //Open xml file
+ if (!xmlDevice->isOpen() && !xmlDevice->open(QIODevice::ReadOnly)) {
+ latestError = ServiceMetaData::SFW_ERROR_UNABLE_TO_OPEN_FILE;
+ parseError = true;
+ } else {
+ //Load xml content
+ xmlReader.setDevice(xmlDevice);
+ // Read XML doc
+ while (!xmlReader.atEnd() && !parseError) {
+ xmlReader.readNext();
+ //Found <SFW> xml versioning tag introduced in 1.1
+ //If this tag is not found the XML parser version will be 1.0
+ if (xmlReader.isStartElement() && xmlReader.name() == QLatin1String(SERVICEFW_TAG)) {
+ if (!processVersionElement(xmlReader)) {
+ parseError = true;
+ }
+ }
+ //Found a <service> node, read service related metadata
+ else if (xmlReader.isStartElement() && xmlReader.name() == QLatin1String(SERVICE_TAG)) {
+ if (!processServiceElement(xmlReader)) {
+ parseError = true;
+ }
+ }
+ else if (xmlReader.isStartElement() && xmlReader.name() != QLatin1String(SERVICE_TAG)
+ && xmlReader.name() != QLatin1String(SERVICEFW_TAG)) {
+ latestError = ServiceMetaData::SFW_ERROR_NO_SERVICE;
+ parseError = true;
+ }
+ else if (xmlReader.tokenType() == QXmlStreamReader::Invalid) {
+ latestError = ServiceMetaData::SFW_ERROR_INVALID_XML_FILE;
+ parseError = true;
+ }
+ }
+ if (ownsXmlDevice)
+ xmlDevice->close();
+ }
+
+ if (parseError) {
+ //provide better error reports
+ switch (latestError) {
+ case SFW_ERROR_NO_SERVICE: /* Can not find service root node in XML file*/
+ qDebug() << "Missing <service> tag";
+ break;
+ case SFW_ERROR_NO_SERVICE_NAME: /* Can not find service name in XML file */
+ qDebug() << "Missing or empty <name> tag within <service>";
+ break;
+ case SFW_ERROR_NO_SERVICE_PATH: /* Can not find service filepath or ipcaddress in XML file */
+ if (greaterThan(xmlVersion, QLatin1String("1.0")))
+ qDebug() << "Missing or empty <filepath> or <ipcaddress> tag within <service>";
+ else
+ qDebug() << "Missing or empty <filepath> tag within <service>";
+ break;
+ case SFW_ERROR_NO_SERVICE_INTERFACE: /* No interface for the service in XML file*/
+ qDebug() << "Missing <interface> tag";
+ break;
+ case SFW_ERROR_NO_INTERFACE_VERSION: /* Can not find interface version in XML file */
+ qDebug() << "Missing or empty <version> tag within <interface>";
+ break;
+ case SFW_ERROR_NO_INTERFACE_NAME: /* Can not find interface name in XML file*/
+ qDebug() << "Missing or empty <name> tag within <interface>";
+ break;
+ case SFW_ERROR_UNABLE_TO_OPEN_FILE: /* Error opening XML file*/
+ qDebug() << "Unable to open service xml file";
+ break;
+ case SFW_ERROR_INVALID_XML_FILE: /* Not a valid XML file*/
+ qDebug() << "Not a valid service xml";
+ break;
+ case SFW_ERROR_PARSE_SERVICE: /* Error parsing service node */
+ qDebug().nospace() << "Invalid tag within <service> with the supplied version("
+ << xmlVersion << ")";
+ break;
+ case SFW_ERROR_PARSE_INTERFACE: /* Error parsing interface node */
+ qDebug() << "Invalid tag within <interface> tags";
+ break;
+ case SFW_ERROR_DUPLICATED_INTERFACE: /* The same interface is defined twice */
+ qDebug() << "The same interface has been defined more than once";
+ break;
+ case SFW_ERROR_INVALID_VERSION:
+ qDebug() << "Invalid version string, expected: x.y";
+ break;
+ case SFW_ERROR_DUPLICATED_TAG: /* The tag appears twice */
+ qDebug() << "XML tag appears twice";
+ break;
+ case SFW_ERROR_INVALID_CUSTOM_TAG: /* The customproperty tag is not correctly formatted or otherwise incorrect*/
+ qDebug() << "Invalid custom property tag";
+ break;
+ case SFW_ERROR_DUPLICATED_CUSTOM_KEY: /* The customproperty appears twice*/
+ qDebug() << "Same custom property appears multiple times";
+ break;
+ case SFW_ERROR_MULTIPLE_SERVICE_TYPES: /* Both filepath and ipcaddress found in the XML file */
+ qDebug() << "Cannot specify both <filepath> and <ipcaddress> tags within <service>";
+ break;
+ case SFW_ERROR_INVALID_FILEPATH: /* Service path cannot contain IPC prefix */
+ qDebug() << "Invalid service location, avoid private prefixes";
+ break;
+ case SFW_ERROR_INVALID_XML_VERSION: /* Error parsing servicefw version node */
+ qDebug() << "Invalid or missing version attribute in <SFW> tag";
+ break;
+ case SFW_ERROR_UNSUPPORTED_IPC: /* Servicefw version doesn't support IPC */
+ qDebug().nospace() << "Supplied service framework version(" << xmlVersion
+ << ") doesn't support the <ipcaddress> tag";
+ break;
+ case SFW_ERROR_UNSUPPORTED_XML_VERSION: /* Unsupported servicefw version supplied */
+ qDebug().nospace() << "Service framework version(" << xmlVersion
+ << ") is higher than available support(" << QLatin1String(XML_MAX) << ")";
+ break;
+ }
+ clearMetadata();
+ }
+ return !parseError;
+}
+
+/*
+ Gets the latest parsing error \n
+ @return parsing error(negative value) or 0 in case there is none
+ */
+int ServiceMetaData::getLatestError() const
+{
+ return latestError;
+}
+
+/*
+ Parses the service framework xml version tag and continues to parse the service
+*/
+bool ServiceMetaData::processVersionElement(QXmlStreamReader &aXMLReader)
+{
+ Q_ASSERT(aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(SERVICEFW_TAG));
+ bool parseError = false;
+
+ if (aXMLReader.attributes().hasAttribute(QLatin1String("version"))) {
+ xmlVersion = aXMLReader.attributes().value(QLatin1String("version")).toString();
+ bool success = checkVersion(xmlVersion);
+
+ if (xmlVersion.isEmpty() || !success) {
+ latestError = ServiceMetaData::SFW_ERROR_INVALID_XML_VERSION;
+ parseError = true;
+ } else {
+ if (greaterThan(xmlVersion, QLatin1String(XML_MAX))) {
+ latestError = ServiceMetaData::SFW_ERROR_UNSUPPORTED_XML_VERSION;
+ parseError = true;
+ }
+ }
+ } else {
+ latestError = ServiceMetaData::SFW_ERROR_INVALID_XML_VERSION;
+ parseError = true;
+ }
+
+ while (!parseError && !aXMLReader.atEnd()) {
+ aXMLReader.readNext();
+ //Found a <service> node, read service related metadata
+ if (aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(SERVICE_TAG)) {
+ if (!processServiceElement(aXMLReader)) {
+ parseError = true;
+ }
+ }
+ else if (aXMLReader.isEndElement() && aXMLReader.name() == QLatin1String(SERVICEFW_TAG)) {
+ //Found </SFW>, leave the loop
+ break;
+ }
+ else if (aXMLReader.isStartElement() && aXMLReader.name() != QLatin1String(SERVICE_TAG)) {
+ latestError = ServiceMetaData::SFW_ERROR_NO_SERVICE;
+ parseError = true;
+ }
+ else if (aXMLReader.tokenType() == QXmlStreamReader::Invalid) {
+ latestError = ServiceMetaData::SFW_ERROR_INVALID_XML_FILE;
+ parseError = true;
+ }
+ }
+
+ return !parseError;
+}
+
+/*
+ Parses and extracts the service metadata from the current xml <service> node \n
+ */
+bool ServiceMetaData::processServiceElement(QXmlStreamReader &aXMLReader)
+{
+ Q_ASSERT(aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(SERVICE_TAG));
+ bool parseError = false;
+
+ int dupSTags[4] = {0 //->tag name
+ ,0 //-> service description
+ ,0 //-> filepath
+ ,0 //-> ipcaddress
+ };
+ while (!parseError && !aXMLReader.atEnd()) {
+ aXMLReader.readNext();
+ if (aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(NAME_TAG)) {
+ //Found <name> tag
+ serviceName = aXMLReader.readElementText();
+ dupSTags[0]++;
+ } else if (aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(DESCRIPTION_TAG)) {
+ //Found <description> tag
+ serviceDescription = aXMLReader.readElementText();
+ dupSTags[1]++;
+ } else if (aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(SERVICE_FILEPATH) ) {
+ //Found <filepath> tag for plugin service
+ dupSTags[2]++;
+ serviceLocation = aXMLReader.readElementText();
+ //Check if IPC prefix was used incorrectly here
+ if (serviceLocation.startsWith(QLatin1String(SERVICE_IPC_PREFIX))) {
+ latestError = ServiceMetaData::SFW_ERROR_INVALID_FILEPATH;
+ parseError = true;
+ }
+ } else if (aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(SERVICE_IPCADDRESS) ) {
+ //Found <ipcaddress> tag for IPC service
+ //Check if servicefw XML version supports IPC
+ if (greaterThan(xmlVersion, QLatin1String("1.0"))) {
+ dupSTags[3]++;
+ serviceLocation = aXMLReader.readElementText();
+ //Check if IPC prefix was used incorrectly here
+ if (serviceLocation.startsWith(QLatin1String(SERVICE_IPC_PREFIX))) {
+ latestError = ServiceMetaData::SFW_ERROR_INVALID_FILEPATH;
+ parseError = true;
+ }
+ } else {
+ latestError = ServiceMetaData::SFW_ERROR_UNSUPPORTED_IPC;
+ parseError = true;
+ }
+ } else if (aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(INTERFACE_TAG)) {
+ //Found interface> node, read module related metadata
+ if (!processInterfaceElement(aXMLReader))
+ parseError = true;
+ } else if (aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String("version")) {
+ //Found <version> tag on service level. We ignore this for now
+ aXMLReader.readElementText();
+ } else if (aXMLReader.isEndElement() && aXMLReader.name() == QLatin1String(SERVICE_TAG)) {
+ //Found </service>, leave the loop
+ break;
+ } else if (aXMLReader.isEndElement() || aXMLReader.isStartElement()) {
+ latestError = ServiceMetaData::SFW_ERROR_PARSE_SERVICE;
+ parseError = true;
+ } else if (aXMLReader.tokenType() == QXmlStreamReader::Invalid) {
+ latestError = ServiceMetaData::SFW_ERROR_INVALID_XML_FILE;
+ parseError = true;
+ }
+ }
+
+ if ( !parseError ) {
+ if (serviceName.isEmpty()) {
+ latestError = ServiceMetaData::SFW_ERROR_NO_SERVICE_NAME;
+ parseError = true;
+ } else if (serviceLocation.isEmpty()) {
+ latestError = ServiceMetaData::SFW_ERROR_NO_SERVICE_PATH;
+ parseError = true;
+ }
+ }
+
+ if (dupSTags[3] > 0)
+ serviceType = QService::InterProcess;
+
+ if ((dupSTags[2] > 0) && (dupSTags[3] > 0)) {
+ latestError = SFW_ERROR_MULTIPLE_SERVICE_TYPES;
+ parseError = true;
+ }
+
+ for (int i=0; !parseError && i<4; i++) {
+ if (dupSTags[i] > 1) {
+ latestError = SFW_ERROR_DUPLICATED_TAG;
+ parseError = true;
+ break;
+ }
+ }
+
+ //update all interfaces with service data
+ const int icount = serviceInterfaces.count();
+ if (icount == 0 && latestError == 0) {
+ latestError = ServiceMetaData::SFW_ERROR_NO_SERVICE_INTERFACE;
+ parseError = true;
+ }
+ for (int i = 0; i<icount; i++) {
+ serviceInterfaces.at(i).d->serviceName = serviceName;
+ serviceInterfaces.at(i).d->attributes[QServiceInterfaceDescriptor::Location] = serviceLocation;
+ serviceInterfaces.at(i).d->attributes[QServiceInterfaceDescriptor::ServiceDescription] = serviceDescription;
+ serviceInterfaces.at(i).d->attributes[QServiceInterfaceDescriptor::ServiceType] = serviceType;
+ }
+
+ return !parseError;
+}
+
+/*
+ Parses and extracts the interface metadata from the current xml <interface> node \n
+*/
+bool ServiceMetaData::processInterfaceElement(QXmlStreamReader &aXMLReader)
+{
+ Q_ASSERT(aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(INTERFACE_TAG));
+ bool parseError = false;
+
+ //Read interface parameter
+ QString tmp;
+ QServiceInterfaceDescriptor aInterface;
+ int dupITags[4] = {
+ 0, //->iface name tag
+ 0, //->version
+ 0, //->capabilities
+ 0 //->description
+ };
+ aInterface.d = new QServiceInterfaceDescriptorPrivate;
+
+ while (!parseError && !aXMLReader.atEnd()) {
+ aXMLReader.readNext();
+ //Read interface description
+ if (aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(NAME_TAG)) {
+ aInterface.d->interfaceName = aXMLReader.readElementText();
+ dupITags[0]++;
+ //Found <name> tag for interface
+ } else if (aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(DESCRIPTION_TAG)) {
+ //Found <description> tag
+ aInterface.d->attributes[QServiceInterfaceDescriptor::InterfaceDescription] = aXMLReader.readElementText();
+ dupITags[3]++;
+ //Found </interface>, leave the loop
+ } else if (aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(INTERFACE_VERSION)) {
+ tmp.clear();
+ tmp = aXMLReader.readElementText();
+ if (tmp.isEmpty())
+ continue; //creates NO_INTERFACE_VERSION error further below
+ bool success = checkVersion(tmp);
+ if ( success ) {
+ int majorVer = -1;
+ int minorVer = -1;
+ transformVersion(tmp, &majorVer, &minorVer);
+ aInterface.d->major = majorVer;
+ aInterface.d->minor = minorVer;
+ dupITags[1]++;
+ } else {
+ latestError = ServiceMetaData::SFW_ERROR_INVALID_VERSION;
+ parseError = true;
+ }
+ } else if (aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(INTERFACE_CAPABILITY)) {
+ tmp.clear();
+ tmp= aXMLReader.readElementText();
+ aInterface.d->attributes[QServiceInterfaceDescriptor::Capabilities] = tmp.split(QLatin1String(","), QString::SkipEmptyParts);
+ dupITags[2]++;
+ } else if (aXMLReader.isStartElement() && aXMLReader.name() == QLatin1String(INTERFACE_CUSTOM_PROPERTY)) {
+ parseError = true;
+ if (aXMLReader.attributes().hasAttribute(QLatin1String("key"))) {
+ const QString ref = aXMLReader.attributes().value(QLatin1String("key")).toString();
+ if (!ref.isEmpty()) {
+ if (aInterface.d->customAttributes.contains(ref)) {
+ latestError = SFW_ERROR_DUPLICATED_CUSTOM_KEY;
+ continue;
+ } else {
+ QString value = aXMLReader.readElementText();
+ if (value.isNull())
+ value = QLatin1String("");
+ aInterface.d->customAttributes[ref] = value;
+ parseError = false;
+ }
+ }
+ }
+ if (parseError)
+ latestError = SFW_ERROR_INVALID_CUSTOM_TAG;
+ } else if (aXMLReader.isEndElement() && aXMLReader.name() == QLatin1String(INTERFACE_TAG)) {
+ break;
+ } else if (aXMLReader.isStartElement() || aXMLReader.isEndElement()) {
+ latestError = ServiceMetaData::SFW_ERROR_PARSE_INTERFACE;
+ parseError = true;
+ } else if (aXMLReader.tokenType() == QXmlStreamReader::Invalid) {
+ latestError = ServiceMetaData::SFW_ERROR_INVALID_XML_FILE;
+ parseError = true;
+ }
+ }
+
+ if (!parseError) {
+ if (dupITags[1] == 0) { //no version tag found
+ latestError = ServiceMetaData::SFW_ERROR_NO_INTERFACE_VERSION;
+ parseError = true;
+ } else if (aInterface.d->interfaceName.isEmpty()) {
+ latestError = ServiceMetaData::SFW_ERROR_NO_INTERFACE_NAME;
+ parseError = true;
+ }
+ }
+
+ for (int i=0;!parseError && i<4;i++) {
+ if (dupITags[i] > 1) {
+ parseError = true;
+ latestError = SFW_ERROR_DUPLICATED_TAG;
+ break;
+ }
+ }
+
+ if (!parseError) {
+ const QString ident = aInterface.d->interfaceName
+ + QString::number(aInterface.majorVersion())
+ + "."
+ + QString::number(aInterface.minorVersion());
+ if (duplicates.contains(ident.toLower())) {
+ latestError = ServiceMetaData::SFW_ERROR_DUPLICATED_INTERFACE;
+ parseError = true;
+ } else {
+ duplicates.insert(ident.toLower());
+ serviceInterfaces.append(aInterface);
+ if (!m_latestIndex.contains(aInterface.d->interfaceName.toLower())
+ || lessThan(latestInterfaceVersion(aInterface.d->interfaceName), aInterface))
+
+ {
+ m_latestIndex[aInterface.d->interfaceName.toLower()] = serviceInterfaces.count() - 1;
+ }
+ }
+ }
+ return !parseError;
+}
+
+QServiceInterfaceDescriptor ServiceMetaData::latestInterfaceVersion(const QString &interfaceName)
+{
+ QServiceInterfaceDescriptor ret;
+ if (m_latestIndex.contains(interfaceName.toLower()))
+ return serviceInterfaces[m_latestIndex[interfaceName.toLower()]];
+ else
+ return ret;
+}
+
+QList<QServiceInterfaceDescriptor> ServiceMetaData::latestInterfaces() const
+{
+ QList<QServiceInterfaceDescriptor> interfaces;
+ QHash<QString,int>::const_iterator i = m_latestIndex.constBegin();
+ while (i != m_latestIndex.constEnd())
+ {
+ interfaces.append(serviceInterfaces[i.value()]);
+ ++i;
+ }
+ return interfaces;
+}
+
+bool ServiceMetaData::lessThan(const QServiceInterfaceDescriptor &d1,
+ const QServiceInterfaceDescriptor &d2) const
+{
+ return (d1.majorVersion() < d2.majorVersion())
+ || ( d1.majorVersion() == d2.majorVersion()
+ && d1.minorVersion() < d2.minorVersion());
+
+}
+
+bool ServiceMetaData::greaterThan(const QString &v1, const QString &v2) const
+{
+ int majorV1 = -1;
+ int minorV1 = -1;
+ transformVersion(v1, &majorV1, &minorV1);
+
+ int majorV2 = -1;
+ int minorV2 = -1;
+ transformVersion(v2, &majorV2, &minorV2);
+
+ return (majorV1 > majorV2
+ || (majorV1 == majorV2 && minorV1 > minorV2));
+}
+
+bool ServiceMetaData::checkVersion(const QString &version) const
+{
+ //match x.y as version format
+ QRegExp rx(QLatin1String("^([1-9][0-9]*)\\.(0+|[1-9][0-9]*)$"));
+ int pos = rx.indexIn(version);
+ QStringList list = rx.capturedTexts();
+ bool success = false;
+ if (pos == 0 && list.count() == 3
+ && rx.matchedLength() == version.length() )
+ {
+ list[1].toInt(&success);
+ if ( success ) {
+ list[2].toInt(&success);
+ }
+ }
+ return success;
+}
+
+void ServiceMetaData::transformVersion(const QString &version, int *major, int *minor) const
+{
+ Q_ASSERT(major != NULL);
+ Q_ASSERT(minor != NULL);
+ if (!checkVersion(version)) {
+ *major = -1;
+ *minor = -1;
+ } else {
+ QRegExp rx(QLatin1String("^([1-9][0-9]*)\\.(0+|[1-9][0-9]*)$"));
+ rx.indexIn(version);
+ QStringList list = rx.capturedTexts();
+ Q_ASSERT(list.count() == 3);
+ *major = list[1].toInt();
+ *minor = list[2].toInt();
+ }
+}
+
+ /*
+ * Clears the service metadata
+ *
+ */
+void ServiceMetaData::clearMetadata()
+{
+ xmlVersion = QLatin1String("1.0");
+ serviceName.clear();
+ serviceLocation.clear();
+ serviceDescription.clear();
+ serviceInterfaces.clear();
+ duplicates.clear();
+ m_latestIndex.clear();
+ serviceType = QService::Plugin;
+}
+
+QTM_END_NAMESPACE
diff --git a/src/serviceframework/servicemetadata_p.h b/src/serviceframework/servicemetadata_p.h
new file mode 100644
index 00000000..48d78dea
--- /dev/null
+++ b/src/serviceframework/servicemetadata_p.h
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** 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 Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SERVICEMETADATA_H
+#define SERVICEMETADATA_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qserviceframeworkglobal.h"
+#include <QXmlStreamReader>
+#include <QStringList>
+#include <QList>
+#include <QSet>
+#include "qserviceinterfacedescriptor.h"
+
+#ifdef SERVICE_XML_GENERATOR
+#undef Q_AUTOTEST_EXPORT
+#define Q_AUTOTEST_EXPORT
+#endif
+
+QT_BEGIN_NAMESPACE
+class QIODevice;
+
+// FORWARD DECLARATIONS
+class QServiceInterfaceDescriptor;
+
+class ServiceMetaDataResults
+{
+public:
+ ServiceMetaDataResults() {}
+
+ ServiceMetaDataResults(const ServiceMetaDataResults& other)
+ {
+ type = other.type;;
+ location = other.location;
+ name = other.name;
+ description = other.description;
+ interfaces = other.interfaces;
+ latestInterfaces = other.latestInterfaces;
+ }
+
+ int type;
+ QString location;
+ QString name;
+ QString description;
+ QList<QServiceInterfaceDescriptor> interfaces;
+ QList<QServiceInterfaceDescriptor> latestInterfaces;
+};
+
+#ifndef QT_NO_DATASTREAM
+Q_AUTOTEST_EXPORT QDataStream &operator<<(QDataStream &, const ServiceMetaDataResults &);
+Q_AUTOTEST_EXPORT QDataStream &operator>>(QDataStream &, ServiceMetaDataResults &);
+#endif
+
+#ifdef IGNORE_SERVICEMETADATA_EXPORT
+ class ServiceMetaData
+#else
+ class Q_AUTOTEST_EXPORT ServiceMetaData
+#endif
+{
+public:
+
+ //! ServiceMetaData::ServiceMetadataErr
+ /*!
+ This enum describes the errors that may be returned by the Service metadata parser.
+ */
+ enum ServiceMetadataErr {
+ SFW_ERROR_NO_SERVICE = 0, /* Can not find service root node in XML file*/
+ SFW_ERROR_NO_SERVICE_NAME, /* Can not find service name in XML file */
+ SFW_ERROR_NO_SERVICE_PATH, /* Can not find service filepath in XML file */
+ SFW_ERROR_NO_SERVICE_INTERFACE, /* No interface for the service in XML file*/
+ SFW_ERROR_NO_INTERFACE_VERSION, /* Can not find interface version in XML file */
+ SFW_ERROR_NO_INTERFACE_NAME, /* Can not find interface name in XML file*/
+ SFW_ERROR_UNABLE_TO_OPEN_FILE, /* Error opening XML file*/
+ SFW_ERROR_INVALID_XML_FILE, /* Not a valid XML file*/
+ SFW_ERROR_PARSE_SERVICE, /* Error parsing service node */
+ SFW_ERROR_PARSE_INTERFACE, /* Error parsing interface node */
+ SFW_ERROR_DUPLICATED_INTERFACE, /* The same interface is defined twice */
+ SFW_ERROR_INVALID_VERSION,
+ SFW_ERROR_DUPLICATED_TAG, /* The tag appears twice */
+ SFW_ERROR_INVALID_CUSTOM_TAG, /* The customproperty tag is not corectly formatted or otherwise incorrect*/
+ SFW_ERROR_DUPLICATED_CUSTOM_KEY, /* The customproperty appears twice*/
+ SFW_ERROR_MULTIPLE_SERVICE_TYPES, /* Both filepath and ipcaddress found in the XML file */
+ SFW_ERROR_INVALID_FILEPATH, /* Service path cannot contain IPC prefix */
+ SFW_ERROR_INVALID_XML_VERSION, /* Error parsing serficefw version node */
+ SFW_ERROR_UNSUPPORTED_IPC, /* Servicefw version doesn't support IPC */
+ SFW_ERROR_UNSUPPORTED_XML_VERSION /* Unsupported servicefw version supplied */
+ };
+
+public:
+
+ ServiceMetaData(const QString &aXmlFilePath);
+
+ ServiceMetaData(QIODevice *device);
+
+ ~ServiceMetaData();
+
+ void setDevice(QIODevice *device);
+
+ QIODevice *device() const;
+
+ bool extractMetadata();
+
+ int getLatestError() const;
+
+ ServiceMetaDataResults parseResults() const;
+
+private:
+ QList<QServiceInterfaceDescriptor> latestInterfaces() const;
+ QServiceInterfaceDescriptor latestInterfaceVersion(const QString &interfaceName);
+ bool processVersionElement(QXmlStreamReader &aXMLReader);
+ bool processServiceElement(QXmlStreamReader &aXMLReader);
+ bool processInterfaceElement(QXmlStreamReader &aXMLReader);
+ void clearMetadata();
+
+private:
+ bool lessThan(const QServiceInterfaceDescriptor &d1,
+ const QServiceInterfaceDescriptor &d2) const;
+ bool greaterThan(const QString &v1, const QString &v2) const;
+ bool checkVersion(const QString &version) const;
+ void transformVersion(const QString &version, int *major, int *minor) const;
+
+ QIODevice *xmlDevice;
+ bool ownsXmlDevice;
+ QString xmlVersion;
+ QString serviceName;
+ QString serviceLocation;
+ QString serviceDescription;
+ QService::Type serviceType;
+ QList<QServiceInterfaceDescriptor> serviceInterfaces;
+ QSet<QString> duplicates;
+ int latestError;
+ QHash<QString, int> m_latestIndex;
+};
+
+QT_END_NAMESPACE
+
+#endif // SERVICEMETADATA_H
diff --git a/src/src.pro b/src/src.pro
index f86b6d77..2d2a1182 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -1,3 +1,3 @@
TEMPLATE = subdirs
CONFIG += ordered
-SUBDIRS = systeminfo publishsubscribe imports
+SUBDIRS = systeminfo publishsubscribe serviceframework imports