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
39QT_BEGIN_NAMESPACE
40
41DatabaseFileWatcher::DatabaseFileWatcher(DatabaseManager *parent)
42 : QObject(parent),
43 m_manager(parent),
44 m_watcher(0)
45{
46}
47
48QString 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
59void 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
107void 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
133void 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
141void 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
153void 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
194bool 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*/
238DatabaseManager::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*/
253DatabaseManager::~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*/
279void 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*/
315bool 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*/
351bool 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 */
387bool 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*/
410QList<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*/
461QStringList 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*/
510QServiceInterfaceDescriptor 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*/
609bool 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*/
647bool 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*/
706bool 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*/
801QServiceInterfaceDescriptor 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*/
820void 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
829QT_END_NAMESPACE
830

source code of qtsystems/src/serviceframework/databasemanager.cpp