File indexing completed on 2024-12-01 04:19:10

0001 /* This file is part of the KDE project
0002    Copyright (C) 2003 Daniel Molkentin <molkentin@kde.org>
0003    Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
0004    Copyright (C) 2003-2015 Jarosław Staniek <staniek@kde.org>
0005    Copyright (C) 2012 Dimitrios T. Tanis <dimitrios.tanis@kdemail.net>
0006 
0007    This program is free software; you can redistribute it and/or
0008    modify it under the terms of the GNU Library General Public
0009    License as published by the Free Software Foundation; either
0010    version 2 of the License, or (at your option) any later version.
0011 
0012    This program is distributed in the hope that it will be useful,
0013    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015    Library General Public License for more details.
0016 
0017    You should have received a copy of the GNU Library General Public License
0018    along with this program; see the file COPYING.  If not, write to
0019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020  * Boston, MA 02110-1301, USA.
0021 */
0022 
0023 #include "KDbDriverManager.h"
0024 #include "KDbDriverManager_p.h"
0025 #include "KDbJsonTrader_p.h"
0026 #include "KDbDriver.h"
0027 #include "KDbDriverMetaData.h"
0028 #include "kdb_debug.h"
0029 
0030 #include <KPluginFactory>
0031 
0032 #include <QApplication>
0033 #include <QMimeDatabase>
0034 #include <QTime>
0035 #include <QWidget>
0036 
0037 Q_GLOBAL_STATIC(DriverManagerInternal, s_self)
0038 
0039 DriverManagerInternal::DriverManagerInternal()
0040  : m_lookupDriversNeeded(true)
0041 {
0042     qsrand(QTime::currentTime().msec()); // needed e.g. to create random table names
0043 }
0044 
0045 DriverManagerInternal::~DriverManagerInternal()
0046 {
0047     drivermanagerDebug();
0048     clear();
0049     drivermanagerDebug() << "ok";
0050 }
0051 
0052 void DriverManagerInternal::clear()
0053 {
0054     drivermanagerDebug() << "Clearing drivers...";
0055     qDeleteAll(m_drivers);
0056     m_drivers.clear();
0057     qDeleteAll(m_driversMetaData);
0058     m_driversMetaData.clear();
0059 }
0060 
0061 void DriverManagerInternal::slotAppQuits()
0062 {
0063     if (qApp && !qApp->topLevelWidgets().isEmpty()
0064             && qApp->topLevelWidgets().first()->isVisible()) {
0065         return; //what a hack! - we give up when app is still there
0066     }
0067     clear();
0068 }
0069 
0070 //static
0071 DriverManagerInternal *DriverManagerInternal::self()
0072 {
0073     return s_self;
0074 }
0075 
0076 bool DriverManagerInternal::lookupDrivers()
0077 {
0078     if (!m_lookupDriversNeeded)
0079         return true;
0080 
0081     if (!forceEmpty) {
0082         lookupDriversInternal();
0083         m_lookupDriversNeeded = false;
0084     }
0085     if (m_driversMetaData.isEmpty()) {
0086         m_result = KDbResult(ERR_DRIVERMANAGER,
0087                              tr("Could not find any database drivers."));
0088         return false;
0089     }
0090     return true;
0091 }
0092 
0093 void DriverManagerInternal::lookupDriversInternal()
0094 {
0095     if (qApp) {
0096         connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(slotAppQuits()));
0097     }
0098 
0099     clearResult();
0100 
0101     //drivermanagerDebug() << "Load all plugins";
0102     QList<QPluginLoader*> offers
0103             = KDbJsonTrader::self()->query(QLatin1String("KDb/Driver"));
0104     const QString expectedVersion = QString::fromLatin1("%1.%2")
0105             .arg(KDB_STABLE_VERSION_MAJOR).arg(KDB_STABLE_VERSION_MINOR);
0106     QMimeDatabase mimedb;
0107     foreach(const QPluginLoader *loader, offers) {
0108         //QJsonObject json = loader->metaData();
0109         //drivermanagerDebug() << json;
0110         QScopedPointer<KDbDriverMetaData> metaData(new KDbDriverMetaData(*loader));
0111         //qDebug() << "VER:" << metaData->version();
0112         if (metaData->version() != expectedVersion) {
0113             kdbWarning() << "Driver with ID" << metaData->id()
0114                          << "(" << metaData->fileName() << ")"
0115                          << "has version" << metaData->version() << "but expected version is"
0116                          << expectedVersion
0117                          << "-- skipping it";
0118             continue;
0119         }
0120         if (m_driversMetaData.contains(metaData->id())) {
0121             if (qEnvironmentVariableIsEmpty("KDB_NO_DUPLICATED_DRIVER_WARNINGS")) {
0122                 kdbWarning() << "Driver with ID" << metaData->id() << "already found at"
0123                              << m_driversMetaData.value(metaData->id())->fileName()
0124                              << "-- skipping another at" << metaData->fileName();
0125             }
0126             continue;
0127         }
0128         QSet<QString> resolvedMimeTypes;
0129         for (const QString &mimeType : metaData->mimeTypes()) {
0130             const QMimeType mime = mimedb.mimeTypeForName(mimeType);
0131             if (!mime.isValid()) {
0132                 kdbWarning() << "Driver with ID" << metaData->id()
0133                              << "specifies the unknown MIME type"
0134                              << mimeType;
0135                 continue;
0136             }
0137            resolvedMimeTypes.insert(mime.name());
0138         }
0139         for (const QString &mimeType : resolvedMimeTypes) {
0140             m_metadata_by_mimetype.insertMulti(mimeType, metaData.data());
0141         }
0142         m_driversMetaData.insert(metaData->id(), metaData.data());
0143         metaData.take();
0144     }
0145     qDeleteAll(offers);
0146     offers.clear();
0147 }
0148 
0149 QStringList DriverManagerInternal::driverIds()
0150 {
0151     if (!lookupDrivers()) {
0152         return QStringList();
0153     }
0154     if (m_driversMetaData.isEmpty() && result().isError()) {
0155         return QStringList();
0156     }
0157     return m_driversMetaData.keys();
0158 }
0159 
0160 const KDbDriverMetaData* DriverManagerInternal::driverMetaData(const QString &id)
0161 {
0162     if (!lookupDrivers()) {
0163         return nullptr;
0164     }
0165     const KDbDriverMetaData *metaData = m_driversMetaData.value(id.toLower());
0166     if (!metaData || m_result.isError()) {
0167         m_result = KDbResult(ERR_DRIVERMANAGER,
0168                              tr("Could not find database driver \"%1\".").arg(id));
0169     }
0170     return metaData;
0171 }
0172 
0173 QStringList DriverManagerInternal::driverIdsForMimeType(const QString &mimeType)
0174 {
0175     if (!lookupDrivers()) {
0176         return QStringList();
0177     }
0178     QMimeDatabase mimedb;
0179     const QMimeType mime = mimedb.mimeTypeForName(mimeType.toLower());
0180     if (!mime.isValid()) {
0181         return QStringList();
0182     }
0183     const QList<KDbDriverMetaData*> metaDatas(m_metadata_by_mimetype.values(mime.name()));
0184     QStringList result;
0185     foreach (const KDbDriverMetaData* metaData, metaDatas) {
0186         result.append(metaData->id());
0187     }
0188     return result;
0189 }
0190 
0191 QStringList DriverManagerInternal::possibleProblems() const
0192 {
0193     return m_possibleProblems;
0194 }
0195 
0196 KDbDriver* DriverManagerInternal::driver(const QString& id)
0197 {
0198     if (!lookupDrivers())
0199         return nullptr;
0200 
0201     clearResult();
0202     drivermanagerDebug() << "loading" << id;
0203 
0204     KDbDriver *driver = nullptr;
0205     if (!id.isEmpty()) {
0206         driver = m_drivers.value(id.toLower());
0207     }
0208     if (driver)
0209         return driver; //cached
0210 
0211     if (!m_driversMetaData.contains(id.toLower())) {
0212         m_result = KDbResult(ERR_DRIVERMANAGER,
0213                              tr("Could not find database driver \"%1\".").arg(id));
0214         return nullptr;
0215     }
0216 
0217     const KDbDriverMetaData *metaData = m_driversMetaData.value(id.toLower());
0218     KPluginFactory *factory = qobject_cast<KPluginFactory*>(metaData->instantiate());
0219     if (!factory) {
0220         m_result = KDbResult(ERR_DRIVERMANAGER,
0221                              tr("Could not load database driver's plugin file \"%1\".")
0222                                 .arg(metaData->fileName()));
0223         QPluginLoader loader(metaData->fileName()); // use this to get the message
0224         (void)loader.load();
0225         m_result.setServerMessage(loader.errorString());
0226         kdbWarning() << m_result.message() << m_result.serverMessage();
0227         return nullptr;
0228     }
0229     driver = factory->create<KDbDriver>();
0230     if (!driver) {
0231         m_result = KDbResult(ERR_DRIVERMANAGER,
0232                              tr("Could not open database driver \"%1\" from plugin file \"%2\".")
0233                                 .arg(metaData->id(),
0234                                      metaData->fileName()));
0235         kdbWarning() << m_result.message();
0236         return nullptr;
0237     }
0238     driver->setMetaData(metaData);
0239     m_drivers.insert(id.toLower(), driver);
0240     return driver;
0241 }
0242 
0243 // ---------------------------
0244 
0245 KDbDriverManager::KDbDriverManager()
0246 {
0247 }
0248 
0249 KDbDriverManager::~KDbDriverManager()
0250 {
0251 }
0252 
0253 KDbResult KDbDriverManager::result() const
0254 {
0255     return s_self->result();
0256 }
0257 
0258 KDbResultable* KDbDriverManager::resultable() const
0259 {
0260     return s_self;
0261 }
0262 
0263 QStringList KDbDriverManager::driverIds()
0264 {
0265     return s_self->driverIds();
0266 }
0267 
0268 const KDbDriverMetaData* KDbDriverManager::driverMetaData(const QString &id)
0269 {
0270     return s_self->driverMetaData(id);
0271 }
0272 
0273 QStringList KDbDriverManager::driverIdsForMimeType(const QString &mimeType)
0274 {
0275     return s_self->driverIdsForMimeType(mimeType);
0276 }
0277 
0278 KDbDriver* KDbDriverManager::driver(const QString& id)
0279 {
0280     return s_self->driver(id);
0281 }
0282 
0283 QString KDbDriverManager::possibleProblemsMessage() const
0284 {
0285     if (s_self->possibleProblems().isEmpty()) {
0286         return QString();
0287     }
0288     QString str;
0289     str.reserve(1024);
0290     str = QLatin1String("<ul>");
0291     foreach (const QString& problem, s_self->possibleProblems())
0292         str += (QLatin1String("<li>") + problem + QLatin1String("</li>"));
0293     str += QLatin1String("</ul>");
0294     return str;
0295 }
0296 
0297 bool KDbDriverManager::hasDatabaseServerDrivers()
0298 {
0299     foreach(const QString& id, driverIds()) {
0300         const KDbDriverMetaData *metaData = s_self->driverMetaData(id);
0301         if (!metaData->isFileBased()) {
0302             return true;
0303         }
0304     }
0305     return false;
0306 }