| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). | 
| 4 | ** Contact: http://www.qt-project.org/legal | 
| 5 | ** | 
| 6 | ** This file is part of the QtSystems module of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:LGPL21$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see http://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at http://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU Lesser General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
| 19 | ** General Public License version 2.1 or version 3 as published by the Free | 
| 20 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and | 
| 21 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the | 
| 22 | ** following information to ensure the GNU Lesser General Public License | 
| 23 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and | 
| 24 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | 
| 25 | ** | 
| 26 | ** As a special exception, The Qt Company gives you certain additional | 
| 27 | ** rights. These rights are described in The Qt Company LGPL Exception | 
| 28 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | 
| 29 | ** | 
| 30 | ** $QT_END_LICENSE$ | 
| 31 | ** | 
| 32 | ****************************************************************************/ | 
| 33 |  | 
| 34 | #include "databasemanager_p.h" | 
| 35 | #include "qserviceinterfacedescriptor_p.h" | 
| 36 | #include <QFileSystemWatcher> | 
| 37 | #include <QHash> | 
| 38 |  | 
| 39 | QT_BEGIN_NAMESPACE | 
| 40 |  | 
| 41 | DatabaseFileWatcher::DatabaseFileWatcher(DatabaseManager *parent) | 
| 42 |     : QObject(parent), | 
| 43 |       m_manager(parent), | 
| 44 |       m_watcher(0) | 
| 45 | { | 
| 46 | } | 
| 47 |  | 
| 48 | QString DatabaseFileWatcher::closestExistingParent(const QString &path) | 
| 49 | { | 
| 50 |     if (QFile::exists(fileName: path)) | 
| 51 |         return path; | 
| 52 |  | 
| 53 |     int lastSep = path.lastIndexOf(c: QDir::separator()); | 
| 54 |     if (lastSep < 0) | 
| 55 |         return QString(); | 
| 56 |     return closestExistingParent(path: path.mid(position: 0, n: lastSep)); | 
| 57 | } | 
| 58 |  | 
| 59 | void DatabaseFileWatcher::restartDirMonitoring(const QString &dbPath, const QString &previousDirPath) | 
| 60 | { | 
| 61 |     if (m_watcher->files().contains(str: dbPath)) | 
| 62 |         return; | 
| 63 |  | 
| 64 |     QString existing = closestExistingParent(path: dbPath); | 
| 65 |     if (existing.isEmpty()) { | 
| 66 |         qWarning() << "QServiceManager: can't find existing directory for path to database"  << dbPath | 
| 67 |             << "serviceAdded() and serviceRemoved() will not be emitted" ; | 
| 68 |         return; | 
| 69 |     } | 
| 70 |     if (existing == dbPath) { | 
| 71 |         ServiceDatabase *db = 0; | 
| 72 |         DatabaseManager::DbScope scope; | 
| 73 |         if (m_manager->m_userDb && dbPath == m_manager->m_userDb->databasePath()) { | 
| 74 |             db = m_manager->m_userDb; | 
| 75 |             scope = DatabaseManager::UserOnlyScope; | 
| 76 |         } else if (dbPath == m_manager->m_systemDb->databasePath()) { | 
| 77 |             db = m_manager->m_systemDb; | 
| 78 |             scope = DatabaseManager::SystemScope; | 
| 79 |         } | 
| 80 |  | 
| 81 |         if (db) { | 
| 82 |             if (!previousDirPath.isEmpty()) | 
| 83 |                 m_watcher->removePath(file: previousDirPath); | 
| 84 |             QMutableListIterator<QString> i(m_monitoredDbPaths); | 
| 85 |             while (i.hasNext()) { | 
| 86 |                 if (i.next() == dbPath) | 
| 87 |                     i.remove(); | 
| 88 |             } | 
| 89 |  | 
| 90 |             QStringList newServices = m_manager->getServiceNames(interfaceName: QString(), scope); | 
| 91 |             for (int i=0; i<newServices.count(); i++) | 
| 92 |                 emit m_manager->serviceAdded(serviceName: newServices[i], scope); | 
| 93 |             setEnabled(database: db, enabled: true); | 
| 94 |         } | 
| 95 |     } else { | 
| 96 |         if (previousDirPath != existing) { | 
| 97 |             if (!previousDirPath.isEmpty()) | 
| 98 |                 m_watcher->removePath(file: previousDirPath); | 
| 99 |             if (!m_watcher->directories().contains(str: existing)) | 
| 100 |                 m_watcher->addPath(file: existing); | 
| 101 |             if (!m_monitoredDbPaths.contains(str: dbPath)) | 
| 102 |                 m_monitoredDbPaths << dbPath; | 
| 103 |         } | 
| 104 |     } | 
| 105 | } | 
| 106 |  | 
| 107 | void DatabaseFileWatcher::setEnabled(ServiceDatabase *database, bool enabled) | 
| 108 | { | 
| 109 |     if (!m_watcher) { | 
| 110 |         m_watcher = new QFileSystemWatcher(this); | 
| 111 |         connect(asender: m_watcher, SIGNAL(fileChanged(QString)), | 
| 112 |             SLOT(databaseChanged(QString))); | 
| 113 |         connect(asender: m_watcher, SIGNAL(directoryChanged(QString)), | 
| 114 |             SLOT(databaseDirectoryChanged(QString))); | 
| 115 |     } | 
| 116 |  | 
| 117 |     QString path = database->databasePath(); | 
| 118 |     if (enabled) { | 
| 119 |         if (QFile::exists(fileName: path)) { | 
| 120 |             if (!database->isOpen()) | 
| 121 |                 database->open(); | 
| 122 |             m_knownServices[path] = database->getServiceNames(interfaceName: QString()); | 
| 123 |             m_watcher->addPath(file: path); | 
| 124 |         } else { | 
| 125 |             restartDirMonitoring(dbPath: path, previousDirPath: QString()); | 
| 126 |         } | 
| 127 |     } else { | 
| 128 |         m_watcher->removePath(file: path); | 
| 129 |         m_knownServices.remove(akey: path); | 
| 130 |     } | 
| 131 | } | 
| 132 |  | 
| 133 | void DatabaseFileWatcher::databaseDirectoryChanged(const QString &path) | 
| 134 | { | 
| 135 |     for (int i=0; i<m_monitoredDbPaths.count(); i++) { | 
| 136 |         if (m_monitoredDbPaths[i].contains(s: path)) | 
| 137 |             restartDirMonitoring(dbPath: m_monitoredDbPaths[i], previousDirPath: path); | 
| 138 |     } | 
| 139 | } | 
| 140 |  | 
| 141 | void DatabaseFileWatcher::databaseChanged(const QString &path) | 
| 142 | { | 
| 143 |     if (m_manager->m_userDb && path == m_manager->m_userDb->databasePath()) | 
| 144 |         notifyChanges(database: m_manager->m_userDb, scope: DatabaseManager::UserScope); | 
| 145 |     else if (path == m_manager->m_systemDb->databasePath()) | 
| 146 |         notifyChanges(database: m_manager->m_systemDb, scope: DatabaseManager::SystemScope); | 
| 147 |  | 
| 148 |     // if database was deleted, the path may have been dropped | 
| 149 |     if (!m_watcher->files().contains(str: path) && QFile::exists(fileName: path)) | 
| 150 |         m_watcher->addPath(file: path); | 
| 151 | } | 
| 152 |  | 
| 153 | void DatabaseFileWatcher::notifyChanges(ServiceDatabase *database, DatabaseManager::DbScope scope) | 
| 154 | { | 
| 155 |     QString dbPath = database->databasePath(); | 
| 156 |     if (!QFile::exists(fileName: dbPath)) { | 
| 157 |         m_knownServices.remove(akey: dbPath); | 
| 158 |         restartDirMonitoring(dbPath, previousDirPath: QString()); | 
| 159 |         return; | 
| 160 |     } | 
| 161 |  | 
| 162 |     QStringList currentServices = database->getServiceNames(interfaceName: QString()); | 
| 163 |     if (database->lastError().code() !=DBError::NoError) { | 
| 164 |         qWarning(msg: "QServiceManager: failed to get current service names for serviceAdded() and serviceRemoved() signals" ); | 
| 165 |         return; | 
| 166 |     } | 
| 167 |  | 
| 168 |     const QStringList &knownServicesRef = m_knownServices[dbPath]; | 
| 169 |  | 
| 170 |     QSet<QString> currentServicesSet = currentServices.toSet(); | 
| 171 |     QSet<QString> knownServicesSet = knownServicesRef.toSet(); | 
| 172 |     if (currentServicesSet == knownServicesSet) | 
| 173 |         return; | 
| 174 |  | 
| 175 |     QStringList newServices; | 
| 176 |     for (int i=0; i<currentServices.count(); i++) { | 
| 177 |         if (!knownServicesSet.contains(value: currentServices[i])) | 
| 178 |             newServices << currentServices[i]; | 
| 179 |     } | 
| 180 |  | 
| 181 |     QStringList removedServices; | 
| 182 |     for (int i=0; i<knownServicesRef.count(); i++) { | 
| 183 |         if (!currentServicesSet.contains(value: knownServicesRef[i])) | 
| 184 |             removedServices << knownServicesRef[i]; | 
| 185 |     } | 
| 186 |  | 
| 187 |     m_knownServices[dbPath] = currentServices; | 
| 188 |     for (int i=0; i<newServices.count(); i++) | 
| 189 |         emit m_manager->serviceAdded(serviceName: newServices[i], scope); | 
| 190 |     for (int i=0; i<removedServices.count(); i++) | 
| 191 |         emit m_manager->serviceRemoved(serviceName: removedServices[i], scope); | 
| 192 | } | 
| 193 |  | 
| 194 | bool lessThan(const QServiceInterfaceDescriptor &d1, | 
| 195 |                                         const QServiceInterfaceDescriptor &d2) | 
| 196 | { | 
| 197 |         return (d1.majorVersion() < d2.majorVersion()) | 
| 198 |                 || ( d1.majorVersion() == d2.majorVersion() | 
| 199 |                 && d1.minorVersion() < d2.minorVersion()); | 
| 200 | } | 
| 201 |  | 
| 202 | /* | 
| 203 |     \class DatabaseManager | 
| 204 |     The database manager is responsible for receiving queries about | 
| 205 |     services and managing user and system scope databases in order to | 
| 206 |     respond to those queries. | 
| 207 |  | 
| 208 |     It provides operations for | 
| 209 |     - registering and unregistering services | 
| 210 |     - querying for services and interfaces | 
| 211 |     - setting and getting default interface implementations | 
| 212 |  | 
| 213 |     and provides notifications by emitting signals for added | 
| 214 |     or removed services. | 
| 215 |  | 
| 216 |     Implementation note: | 
| 217 |     When one of the above operations is first invoked a connection with the | 
| 218 |     appropriate database(s) is opened.  This connection remains | 
| 219 |     open until the DatabaseManager is destroyed. | 
| 220 |  | 
| 221 |     If the system scope database cannot be opened when performing | 
| 222 |     user scope operations.  The operations are carried out as per normal | 
| 223 |     but only acting on the user scope database.  Each operation invokation | 
| 224 |     will try to open a connection with the system scope database. | 
| 225 |  | 
| 226 |     Terminology note: | 
| 227 |     When referring to user scope regarding operations, it generally | 
| 228 |     means access to both the user and system databases with the | 
| 229 |     data from both combined into a single dataset. | 
| 230 |     When referring to a user scope database it means the | 
| 231 |     user database only. | 
| 232 |  | 
| 233 | */ | 
| 234 |  | 
| 235 | /* | 
| 236 |    Constructor | 
| 237 | */ | 
| 238 | DatabaseManager::DatabaseManager() | 
| 239 |     : m_userDb(NULL), | 
| 240 |       m_systemDb(new ServiceDatabase), | 
| 241 |       m_fileWatcher(0), | 
| 242 |       m_hasAccessedUserDb(false), | 
| 243 |       m_alreadyWarnedOpenError(false) | 
| 244 | { | 
| 245 |     m_userDb = new ServiceDatabase; | 
| 246 |     initDbPath(scope: UserScope); | 
| 247 |     initDbPath(scope: SystemScope); | 
| 248 | } | 
| 249 |  | 
| 250 | /* | 
| 251 |    Destructor | 
| 252 | */ | 
| 253 | DatabaseManager::~DatabaseManager() | 
| 254 | { | 
| 255 |     delete m_fileWatcher; | 
| 256 |     m_fileWatcher = 0; | 
| 257 |  | 
| 258 |     //Aside: databases are implicitly closed | 
| 259 |     //during deletion | 
| 260 |     if (m_userDb) { | 
| 261 |         m_userDb->close(); | 
| 262 |         delete m_userDb; | 
| 263 |     } | 
| 264 |     m_userDb = 0; | 
| 265 |  | 
| 266 |     if (m_systemDb) { | 
| 267 |         m_systemDb->close(); | 
| 268 |         delete m_systemDb; | 
| 269 |     } | 
| 270 |     m_systemDb = 0; | 
| 271 | } | 
| 272 |  | 
| 273 |  | 
| 274 | /* | 
| 275 |     Initialises database path of m_userDb | 
| 276 |     or m_systemDb, but does not open any | 
| 277 |     database connections | 
| 278 | */ | 
| 279 | void DatabaseManager::initDbPath(DbScope scope) | 
| 280 | { | 
| 281 |     QSettings::Scope settingsScope; | 
| 282 |     QString dbIdentifier; | 
| 283 |     ServiceDatabase *db; | 
| 284 |     if (scope == SystemScope) { | 
| 285 |         settingsScope = QSettings::SystemScope; | 
| 286 |         dbIdentifier = QLatin1String("_system" ); | 
| 287 |         db = m_systemDb; | 
| 288 |     } else { | 
| 289 |         settingsScope = QSettings::UserScope; | 
| 290 |         dbIdentifier = QLatin1String("_user" ); | 
| 291 |         db = m_userDb; | 
| 292 |     } | 
| 293 |  | 
| 294 | #ifdef QT_SIMULATOR | 
| 295 |     dbIdentifier.append(QLatin1String("_simulator" )); | 
| 296 | #endif | 
| 297 |  | 
| 298 |     QSettings settings(QSettings::IniFormat, settingsScope, | 
| 299 |                 QLatin1String("Nokia" ), QLatin1String("QtServiceFramework" )); | 
| 300 |     QFileInfo fi(settings.fileName()); | 
| 301 |     QDir dir = fi.dir(); | 
| 302 |     QString qtVersion = QLatin1String(qVersion()); | 
| 303 |     qtVersion = qtVersion.left(n: qtVersion.size() -2); //strip off patch version | 
| 304 |     QString dbName = QString(QLatin1String("QtServiceFramework_" )) + qtVersion + dbIdentifier + QLatin1String(".db" ); | 
| 305 |     db->setDatabasePath(dir.path() + QDir::separator() + dbName); | 
| 306 | } | 
| 307 |  | 
| 308 | /* | 
| 309 |     Adds the details \a  service into the service database corresponding to | 
| 310 |     \a scope. | 
| 311 |  | 
| 312 |     Returns true if the operation succeeded and false otherwise. | 
| 313 |     The last error is set when this function is called. | 
| 314 | */ | 
| 315 | bool DatabaseManager::registerService(ServiceMetaDataResults &service, DbScope scope) | 
| 316 | { | 
| 317 |     if (scope == DatabaseManager::SystemScope) { | 
| 318 |         if (!openDb(scope: DatabaseManager::SystemScope)) { | 
| 319 |             return false; | 
| 320 |         }  else { | 
| 321 |             if (!m_systemDb->registerService(service)) { | 
| 322 |                 m_lastError = m_systemDb->lastError(); | 
| 323 |                 return false; | 
| 324 |             } else { //must be successful registration | 
| 325 |                 m_lastError.setError(error: DBError::NoError); | 
| 326 |                 return true; | 
| 327 |             } | 
| 328 |         } | 
| 329 |     } else { //must  be registering service at user scope | 
| 330 |         if (!openDb(scope: DatabaseManager::UserScope)) { | 
| 331 |             return false; | 
| 332 |         } else { | 
| 333 |             if (!m_userDb->registerService(service)) { | 
| 334 |                 m_lastError = m_userDb->lastError(); | 
| 335 |                 return false; | 
| 336 |             } else { //must be successful registration | 
| 337 |                 m_lastError.setError(error: DBError::NoError); | 
| 338 |                 return true; | 
| 339 |             } | 
| 340 |         } | 
| 341 |     } | 
| 342 | } | 
| 343 |  | 
| 344 | /* | 
| 345 |     Removes the details of \serviceName from the database corresponding to \a | 
| 346 |     scope. | 
| 347 |  | 
| 348 |     Returns true if the operation succeeded, false otherwise. | 
| 349 |     The last error is set when this function is called. | 
| 350 | */ | 
| 351 | bool DatabaseManager::unregisterService(const QString &serviceName, DbScope scope) | 
| 352 | { | 
| 353 |     if (scope == DatabaseManager::SystemScope) { | 
| 354 |         if (!openDb(scope: DatabaseManager::SystemScope)) | 
| 355 |             return false; | 
| 356 |    else { | 
| 357 |             if (!m_systemDb->unregisterService(serviceName)) { | 
| 358 |                 m_lastError = m_systemDb->lastError(); | 
| 359 |                 return false; | 
| 360 |             } else { //must be successful unregistration | 
| 361 |                 m_lastError.setError(error: DBError::NoError); | 
| 362 |                 return true; | 
| 363 |             } | 
| 364 |         } | 
| 365 |     } else { | 
| 366 |         if (!openDb(scope: DatabaseManager::UserScope)) { | 
| 367 |             return false; | 
| 368 |         } else { | 
| 369 |             if (!m_userDb->unregisterService(serviceName)){ | 
| 370 |                 m_lastError = m_userDb->lastError(); | 
| 371 |                 return false; | 
| 372 |             } else { //must be successful unregistration | 
| 373 |                 m_lastError.setError(error: DBError::NoError); | 
| 374 |                 return true; | 
| 375 |             } | 
| 376 |         } | 
| 377 |     } | 
| 378 | } | 
| 379 |  | 
| 380 | /* | 
| 381 |     Removes the initialization specific information of \serviceName from the database | 
| 382 |     corresponding to a \scope. | 
| 383 |  | 
| 384 |     Returns true if teh operation succeeded, false otherwise. | 
| 385 |     The last error is set when this function is called. | 
| 386 |   */ | 
| 387 | bool DatabaseManager::serviceInitialized(const QString &serviceName, DbScope scope) | 
| 388 | { | 
| 389 |     ServiceDatabase *db = (scope == DatabaseManager::SystemScope) ? m_systemDb : m_userDb; | 
| 390 |  | 
| 391 |     if (!openDb(scope)) { | 
| 392 |         return false; | 
| 393 |     } else { | 
| 394 |         if (!db->serviceInitialized(serviceName)) { | 
| 395 |             m_lastError = db->lastError(); | 
| 396 |             return false; | 
| 397 |         } else { | 
| 398 |             m_lastError.setError(error: DBError::NoError); | 
| 399 |             return true; | 
| 400 |         } | 
| 401 |     } | 
| 402 | } | 
| 403 |  | 
| 404 | /* | 
| 405 |     Retrieves a list of interface descriptors that fulfill the constraints specified | 
| 406 |     by \a filter at a given \a scope. | 
| 407 |  | 
| 408 |     The last error is set when this function is called. | 
| 409 | */ | 
| 410 | QList<QServiceInterfaceDescriptor>  DatabaseManager::getInterfaces(const QServiceFilter &filter, DbScope scope) | 
| 411 | { | 
| 412 |     QList<QServiceInterfaceDescriptor> descriptors; | 
| 413 |  | 
| 414 |     int userDescriptorCount = 0; | 
| 415 |     if (scope == UserScope) { | 
| 416 |         if (!openDb(scope: UserScope)) | 
| 417 |             return descriptors; | 
| 418 |  | 
| 419 |         descriptors =  m_userDb->getInterfaces(filter); | 
| 420 |         if (m_userDb->lastError().code() != DBError::NoError ) { | 
| 421 |             descriptors.clear(); | 
| 422 |             m_lastError = m_userDb->lastError(); | 
| 423 |             return descriptors; | 
| 424 |         } | 
| 425 |  | 
| 426 |         userDescriptorCount = descriptors.count(); | 
| 427 |         for (int i=0; i < userDescriptorCount; ++i) { | 
| 428 |             descriptors[i].d->scope = QService::UserScope; | 
| 429 |         } | 
| 430 |     } | 
| 431 |  | 
| 432 |     if (openDb(scope: SystemScope)) { | 
| 433 |         descriptors.append(t: m_systemDb->getInterfaces(filter)); | 
| 434 |         if (m_systemDb->lastError().code() != DBError::NoError) { | 
| 435 |             descriptors.clear(); | 
| 436 |             m_lastError = m_systemDb->lastError(); | 
| 437 |             return descriptors; | 
| 438 |         } | 
| 439 |  | 
| 440 |         for (int i = userDescriptorCount; i < descriptors.count(); ++i) | 
| 441 |             descriptors[i].d->scope = QService::SystemScope; | 
| 442 |     } else { | 
| 443 |         if ( scope == SystemScope) { | 
| 444 |             //openDb() should already have handled lastError | 
| 445 |             descriptors.clear(); | 
| 446 |             return descriptors; | 
| 447 |         } | 
| 448 |     } | 
| 449 |  | 
| 450 |     m_lastError.setError(error: DBError::NoError); | 
| 451 |     return descriptors; | 
| 452 | } | 
| 453 |  | 
| 454 |  | 
| 455 | /* | 
| 456 |     Retrieves a list of the names of services that provide the interface | 
| 457 |     specified by \a interfaceName. | 
| 458 |  | 
| 459 |     The last error is set when this function is called. | 
| 460 | */ | 
| 461 | QStringList DatabaseManager::getServiceNames(const QString &interfaceName, DatabaseManager::DbScope scope) | 
| 462 | { | 
| 463 |     QStringList serviceNames; | 
| 464 |     if (scope == UserScope || scope == UserOnlyScope) { | 
| 465 |         if (!openDb(scope: DatabaseManager::UserScope)) | 
| 466 |             return serviceNames; | 
| 467 |         serviceNames = m_userDb->getServiceNames(interfaceName); | 
| 468 |         if (m_userDb->lastError().code() != DBError::NoError) { | 
| 469 |             serviceNames.clear(); | 
| 470 |             m_lastError = m_userDb->lastError(); | 
| 471 |             return serviceNames; | 
| 472 |         } | 
| 473 |         if (scope == UserOnlyScope) { | 
| 474 |             m_lastError.setError(error: DBError::NoError); | 
| 475 |             return serviceNames; | 
| 476 |         } | 
| 477 |     } | 
| 478 |  | 
| 479 |     if (openDb(scope: DatabaseManager::SystemScope)) { | 
| 480 |         QStringList systemServiceNames; | 
| 481 |         systemServiceNames = m_systemDb->getServiceNames(interfaceName); | 
| 482 |         if (m_systemDb->lastError().code() != DBError::NoError) { | 
| 483 |             serviceNames.clear(); | 
| 484 |             m_lastError = m_systemDb->lastError(); | 
| 485 |             return serviceNames; | 
| 486 |         } | 
| 487 |         foreach (const QString &systemServiceName, systemServiceNames) { | 
| 488 |             if (!serviceNames.contains(str: systemServiceName, cs: Qt::CaseInsensitive)) | 
| 489 |                 serviceNames.append(t: systemServiceName); | 
| 490 |         } | 
| 491 |  | 
| 492 |     } else { | 
| 493 |         if ( scope == SystemScope) { | 
| 494 |             //openDb() should have already handled lastError | 
| 495 |             serviceNames.clear(); | 
| 496 |             return serviceNames; | 
| 497 |         } | 
| 498 |     } | 
| 499 |  | 
| 500 |     m_lastError.setError(error: DBError::NoError); | 
| 501 |     return serviceNames; | 
| 502 | } | 
| 503 |  | 
| 504 | /* | 
| 505 |     Returns the default interface implementation descriptor for a given | 
| 506 |     \a interfaceName and \a scope. | 
| 507 |  | 
| 508 |     The last error is set when this function is called. | 
| 509 | */ | 
| 510 | QServiceInterfaceDescriptor DatabaseManager::interfaceDefault(const QString &interfaceName, DbScope scope) | 
| 511 | { | 
| 512 |     QServiceInterfaceDescriptor descriptor; | 
| 513 |     if (scope == UserScope) { | 
| 514 |         if (!openDb(scope: UserScope)) | 
| 515 |             return QServiceInterfaceDescriptor(); | 
| 516 |         QString interfaceID; | 
| 517 |         descriptor = m_userDb->interfaceDefault(interfaceName, interfaceID: &interfaceID); | 
| 518 |  | 
| 519 |         if (m_userDb->lastError().code() == DBError::NoError) { | 
| 520 |             descriptor.d->scope = QService::UserScope; | 
| 521 |             return descriptor; | 
| 522 |         } else if (m_userDb->lastError().code() == DBError::ExternalIfaceIDFound) { | 
| 523 |             //default hasn't been found in user db, but we have found an ID | 
| 524 |             //that may refer to an interface implementation in the system db | 
| 525 |             if (!openDb(scope: SystemScope)) { | 
| 526 |                 QString errorText(QLatin1String("No default service found for interface: \"%1\"" )); | 
| 527 |                 m_lastError.setError(error: DBError::NotFound, errorText: errorText.arg(a: interfaceName)); | 
| 528 |                 return QServiceInterfaceDescriptor(); | 
| 529 |             } | 
| 530 |  | 
| 531 |             descriptor = m_systemDb->getInterface(interfaceID); | 
| 532 |             //found the service from the system database | 
| 533 |             if (m_systemDb->lastError().code() == DBError::NoError) { | 
| 534 |                 m_lastError.setError(error: DBError::NoError); | 
| 535 |                 descriptor.d->scope = QService::SystemScope; | 
| 536 |                 return descriptor; | 
| 537 |             } else if (m_systemDb->lastError().code() == DBError::NotFound) { | 
| 538 |                 //service implementing interface doesn't exist in the system db | 
| 539 |                 //so the user db must contain a stale entry so remove it | 
| 540 |                 m_userDb->removeExternalDefaultServiceInterface(interfaceID); | 
| 541 |  | 
| 542 |                 QList<QServiceInterfaceDescriptor> descriptors; | 
| 543 |                 descriptors = getInterfaces(filter: QServiceFilter(interfaceName), scope: UserScope); | 
| 544 |  | 
| 545 |                 //make the latest interface implementation the new | 
| 546 |                 //default if there is one | 
| 547 |                 if (descriptors.count() > 0 ) { | 
| 548 |                     descriptor = latestDescriptor(descriptors); | 
| 549 |                     setInterfaceDefault(serviceInterface: descriptor, scope: UserScope); | 
| 550 |                     m_lastError.setError(error: DBError::NoError); | 
| 551 |                     return descriptor; | 
| 552 |                 } else { | 
| 553 |                     QString errorText(QLatin1String("No default service found for interface: \"%1\"" )); | 
| 554 |                     m_lastError.setError(error: DBError::NotFound, errorText: errorText.arg(a: interfaceName)); | 
| 555 |                     return QServiceInterfaceDescriptor(); | 
| 556 |                 } | 
| 557 |             } else { | 
| 558 |                 m_lastError.setError(error: DBError::NoError); | 
| 559 |                 return QServiceInterfaceDescriptor(); | 
| 560 |             } | 
| 561 |         } else if (m_userDb->lastError().code() == DBError::NotFound) { | 
| 562 |             //do nothing, the search for a default in the system db continues | 
| 563 |             //further down | 
| 564 |         } else { //error occurred at user db level, so return | 
| 565 |             m_lastError = m_userDb->lastError(); | 
| 566 |             return QServiceInterfaceDescriptor(); | 
| 567 |         } | 
| 568 |     } | 
| 569 |  | 
| 570 |     //search at system scope because we haven't found a default at user scope | 
| 571 |     //or because we're specifically only querying at system scope | 
| 572 |     if (!openDb(scope: SystemScope)) { | 
| 573 |         if (scope == SystemScope) { | 
| 574 |             m_lastError = m_systemDb->lastError(); | 
| 575 |             return QServiceInterfaceDescriptor(); | 
| 576 |         } else if (scope == UserScope && m_userDb && m_userDb->lastError().code() == DBError::NotFound) { | 
| 577 |             m_lastError = m_userDb->lastError(); | 
| 578 |             return QServiceInterfaceDescriptor(); | 
| 579 |         } | 
| 580 |     } else { | 
| 581 |         descriptor = m_systemDb->interfaceDefault(interfaceName); | 
| 582 |         if (m_systemDb->lastError().code() == DBError::NoError) { | 
| 583 |             descriptor.d->scope = QService::SystemScope; | 
| 584 |             return descriptor; | 
| 585 |         } else if (m_systemDb->lastError().code() == DBError::NotFound) { | 
| 586 |             m_lastError = m_systemDb->lastError(); | 
| 587 |             return QServiceInterfaceDescriptor(); | 
| 588 |         } else { | 
| 589 |             m_lastError = m_systemDb->lastError(); | 
| 590 |             return QServiceInterfaceDescriptor(); | 
| 591 |         } | 
| 592 |     } | 
| 593 |  | 
| 594 |     //should not be possible to reach here | 
| 595 |     m_lastError.setError(error: DBError::UnknownError); | 
| 596 |     return QServiceInterfaceDescriptor(); | 
| 597 | } | 
| 598 |  | 
| 599 | /* | 
| 600 |     Sets the default interface implemenation for \a interfaceName to the matching | 
| 601 |     interface implementation provided by \a service. | 
| 602 |  | 
| 603 |     If \a service provides more than one interface implementation, the newest | 
| 604 |     version of the interface is set as the default. | 
| 605 |  | 
| 606 |     Returns true if the operation was succeeded, false otherwise | 
| 607 |     The last error is set when this function is called. | 
| 608 | */ | 
| 609 | bool DatabaseManager::setInterfaceDefault(const QString &serviceName, const | 
| 610 |         QString &interfaceName, DbScope scope) | 
| 611 | { | 
| 612 |     QList<QServiceInterfaceDescriptor> descriptors; | 
| 613 |     QServiceFilter filter; | 
| 614 |     filter.setServiceName(serviceName); | 
| 615 |     filter.setInterface(interfaceName); | 
| 616 |  | 
| 617 |     descriptors = getInterfaces(filter, scope); | 
| 618 |     if (m_lastError.code() != DBError::NoError) | 
| 619 |         return false; | 
| 620 |  | 
| 621 |     if (descriptors.count() == 0) { | 
| 622 |         QString errorText(QLatin1String("No implementation for interface \"%1\" "  | 
| 623 |                 "found for service \"%2\"" )); | 
| 624 |         m_lastError.setError(error: DBError::NotFound, | 
| 625 |                 errorText: errorText.arg(a: interfaceName) | 
| 626 |                 .arg(a: serviceName)); | 
| 627 |         return false; | 
| 628 |     } | 
| 629 |  | 
| 630 |     //find the descriptor with the latest version | 
| 631 |     int latestIndex = 0; | 
| 632 |         for (int i = 1; i < descriptors.count(); ++i) { | 
| 633 |             if (lessThan(d1: descriptors[latestIndex], d2: descriptors[i])) | 
| 634 |                 latestIndex = i; | 
| 635 |     } | 
| 636 |  | 
| 637 |     return setInterfaceDefault(serviceInterface: descriptors[latestIndex], scope); | 
| 638 | } | 
| 639 |  | 
| 640 | /* | 
| 641 |     Sets the interface implementation specified by \a descriptor to be the default | 
| 642 |     implementation for the particular interface specified in the descriptor. | 
| 643 |  | 
| 644 |     Returns true if the operation succeeded, false otherwise. | 
| 645 |     The last error is set when this function is called. | 
| 646 | */ | 
| 647 | bool DatabaseManager::setInterfaceDefault(const QServiceInterfaceDescriptor &descriptor, DbScope scope) | 
| 648 | { | 
| 649 |     if (scope == UserScope) { | 
| 650 |         if (!openDb(scope: UserScope)) | 
| 651 |             return false; | 
| 652 |         if (descriptor.scope() == QService::UserScope) { //if a user scope descriptor, just set it in the user db | 
| 653 |             if (m_userDb->setInterfaceDefault(serviceInterface: descriptor)) { | 
| 654 |                 m_lastError.setError(error: DBError::NoError); | 
| 655 |                 return true; | 
| 656 |             } else { | 
| 657 |                 m_lastError = m_userDb->lastError(); | 
| 658 |                 return false; | 
| 659 |             } | 
| 660 |         } else { //otherwise we need to get the interfaceID from the system db and set this | 
| 661 |             //as an external default interface ID in the user db | 
| 662 |             if (!openDb(scope: SystemScope)) | 
| 663 |                 return false; | 
| 664 |  | 
| 665 |             QString interfaceDescriptorID = m_systemDb->getInterfaceID(serviceInterface: descriptor); | 
| 666 |             if (m_systemDb->lastError().code() == DBError::NoError) { | 
| 667 |                 if (m_userDb->setInterfaceDefault(serviceInterface: descriptor, externalInterfaceID: interfaceDescriptorID)) { | 
| 668 |                     m_lastError.setError(error: DBError::NoError); | 
| 669 |                     return true; | 
| 670 |                 } else { | 
| 671 |                     m_lastError = m_userDb->lastError(); | 
| 672 |                     return false; | 
| 673 |                 } | 
| 674 |             } else { | 
| 675 |                 m_lastError = m_systemDb->lastError(); | 
| 676 |                 return false; | 
| 677 |             } | 
| 678 |         } | 
| 679 |     } else {  //scope == SystemScope | 
| 680 |         if (descriptor.scope() == QService::UserScope) { | 
| 681 |             QString errorText(QLatin1String("Cannot set default service at system scope with a user scope "  | 
| 682 |                                             "interface descriptor" )); | 
| 683 |             m_lastError.setError(error: DBError::InvalidDescriptorScope, errorText); | 
| 684 |             return false; | 
| 685 |         } else { | 
| 686 |             if (!openDb(scope: SystemScope)) { | 
| 687 |                 return false; | 
| 688 |             } else { | 
| 689 |                 if (m_systemDb->setInterfaceDefault(serviceInterface: descriptor)) { | 
| 690 |                     m_lastError.setError(error: DBError::NoError); | 
| 691 |                     return true; | 
| 692 |                 } else { | 
| 693 |                     m_lastError = m_systemDb->lastError(); | 
| 694 |                     return false; | 
| 695 |                 } | 
| 696 |             } | 
| 697 |         } | 
| 698 |     } | 
| 699 | } | 
| 700 |  | 
| 701 | /* | 
| 702 |     Opens a database connection with the database at a specific \a scope. | 
| 703 |  | 
| 704 |     The last error is set when this function is called. | 
| 705 | */ | 
| 706 | bool DatabaseManager::openDb(DbScope scope) | 
| 707 | { | 
| 708 |     if (scope == SystemScope && m_systemDb->isOpen() && !QFile::exists(fileName: m_systemDb->databasePath())) { | 
| 709 |         delete m_systemDb; | 
| 710 |         m_systemDb = new ServiceDatabase; | 
| 711 |         initDbPath(scope: SystemScope); | 
| 712 |         m_alreadyWarnedOpenError = false; | 
| 713 |     } else if (scope != SystemScope && m_userDb->isOpen() && !QFile::exists(fileName: m_userDb->databasePath())) { | 
| 714 |         delete m_userDb; | 
| 715 |         m_userDb = new ServiceDatabase; | 
| 716 |         initDbPath(scope: UserScope); | 
| 717 |         m_alreadyWarnedOpenError = false; | 
| 718 |     } | 
| 719 |  | 
| 720 |     ServiceDatabase *db; | 
| 721 |     if (scope == SystemScope) { | 
| 722 |         db = m_systemDb; | 
| 723 |     } | 
| 724 |     else { | 
| 725 |         db = m_userDb; | 
| 726 |         m_hasAccessedUserDb = true; | 
| 727 |     } | 
| 728 |  | 
| 729 |     if (db->isOpen()) | 
| 730 |         return true; | 
| 731 |  | 
| 732 |     bool isOpen = db->open(); | 
| 733 |     if (!isOpen) { | 
| 734 | #ifdef QT_SFW_SERVICEDATABASE_DEBUG | 
| 735 |         qWarning() << "DatabaseManger::openDb():-"  | 
| 736 |                     << "Problem:"  << qPrintable(m_lastError.text()); | 
| 737 | #endif | 
| 738 |         if (scope == SystemScope && m_hasAccessedUserDb == true) { | 
| 739 |                 if (QFile::exists(fileName: m_systemDb->databasePath()) && !m_alreadyWarnedOpenError) | 
| 740 |                     qWarning() << "Service Framework:- Unable to access system database for a user scope "  | 
| 741 |                         "operation; resorting to using only the user database.  Future operations "  | 
| 742 |                         "will attempt to access the system database but no further warnings will be issued" ; | 
| 743 |         } | 
| 744 |  | 
| 745 |         QString warning; | 
| 746 |         if (db->lastError().code() == DBError::InvalidDatabaseFile) { | 
| 747 |             warning = QString(QLatin1String("Service Framework:- Database file is corrupt or invalid: " )) + db->databasePath(); | 
| 748 |             m_lastError = db->lastError(); | 
| 749 |         } else { | 
| 750 |             warning = QString(QLatin1String("Service Framework:- Unable to open or create database at: " )) +  db->databasePath(); | 
| 751 |             QString errorText(QLatin1String("Unable to open service framework database: %1" )); | 
| 752 |             m_lastError.setError(error: DBError::CannotOpenServiceDb, | 
| 753 |                 errorText: errorText.arg(a: db->databasePath())); | 
| 754 |         } | 
| 755 |  | 
| 756 |         if (m_alreadyWarnedOpenError | 
| 757 |                 || (scope == SystemScope && m_hasAccessedUserDb && !QFile::exists(fileName: m_systemDb->databasePath()))) { | 
| 758 |             //do nothing, don't output warning if already warned or we're accessing the system database | 
| 759 |             //from user scope and the system database doesn't exist | 
| 760 |         } else { | 
| 761 |             qWarning() << qPrintable(warning); | 
| 762 |             m_alreadyWarnedOpenError = true; | 
| 763 |         } | 
| 764 |  | 
| 765 |         return false; | 
| 766 |     } | 
| 767 |  | 
| 768 |     //if we are opening the system database while the user database is open, | 
| 769 |     //cleanup and reset any old external defaults | 
| 770 |     //from the user scope database | 
| 771 |     if (scope == SystemScope && m_userDb && m_userDb->isOpen()) { | 
| 772 |         QList<QPair<QString,QString> > externalDefaultsInfo; | 
| 773 |         externalDefaultsInfo = m_userDb->externalDefaultsInfo(); | 
| 774 |         QServiceInterfaceDescriptor descriptor; | 
| 775 |         QPair<QString,QString> defaultInfo; | 
| 776 |  | 
| 777 |         for (int i = 0; i < externalDefaultsInfo.count(); ++i) { | 
| 778 |             defaultInfo = externalDefaultsInfo[i]; | 
| 779 |             descriptor = m_userDb->getInterface(interfaceID: defaultInfo.second); | 
| 780 |             if (m_userDb->lastError().code() == DBError::NotFound) { | 
| 781 |                 m_userDb->removeExternalDefaultServiceInterface(interfaceID: defaultInfo.second); | 
| 782 |                 QList<QServiceInterfaceDescriptor> descriptors; | 
| 783 |                 descriptors = getInterfaces(filter: QServiceFilter(defaultInfo.first), scope: UserScope); | 
| 784 |  | 
| 785 |                 if (descriptors.count() > 0 ) { | 
| 786 |                     descriptor = latestDescriptor(descriptors); | 
| 787 |                     setInterfaceDefault(descriptor, scope: UserScope); | 
| 788 |                 } | 
| 789 |             } | 
| 790 |         } | 
| 791 |     } | 
| 792 |  | 
| 793 |     m_lastError.setError(error: DBError::NoError); | 
| 794 |     return true; | 
| 795 | } | 
| 796 |  | 
| 797 | /* | 
| 798 |     Returns the interface descriptor with the highest version from the | 
| 799 |     list of interface \a descriptors | 
| 800 | */ | 
| 801 | QServiceInterfaceDescriptor DatabaseManager::latestDescriptor( | 
| 802 |                                     const QList<QServiceInterfaceDescriptor> &descriptors) | 
| 803 | { | 
| 804 |     if (descriptors.count() == 0) | 
| 805 |         return QServiceInterfaceDescriptor(); | 
| 806 |  | 
| 807 |     int latestIndex = 0; | 
| 808 |     for (int i = 1; i < descriptors.count(); ++i) { | 
| 809 |         if (lessThan(d1: descriptors[latestIndex], d2: descriptors[i])) | 
| 810 |             latestIndex = i; | 
| 811 |     } | 
| 812 |  | 
| 813 |     return descriptors[latestIndex]; | 
| 814 | } | 
| 815 |  | 
| 816 | /* | 
| 817 |     Sets whether change notifications for added and removed services are | 
| 818 |     \a enabled or not at a given \a scope. | 
| 819 | */ | 
| 820 | void DatabaseManager::setChangeNotificationsEnabled(DbScope scope, bool enabled) | 
| 821 | { | 
| 822 |     if (!m_fileWatcher) m_fileWatcher = new | 
| 823 |     DatabaseFileWatcher(this); m_fileWatcher->setEnabled(database: scope == SystemScope ? | 
| 824 |             m_systemDb : m_userDb, enabled); | 
| 825 | } | 
| 826 |  | 
| 827 | #include "moc_databasemanager_p.cpp" | 
| 828 |  | 
| 829 | QT_END_NAMESPACE | 
| 830 |  |