| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117 | 
							- /*=============================================================================
 
-   Library: CTK
 
-   Copyright (c) German Cancer Research Center,
 
-     Division of Medical and Biological Informatics
 
-   Licensed under the Apache License, Version 2.0 (the "License");
 
-   you may not use this file except in compliance with the License.
 
-   You may obtain a copy of the License at
 
-     http://www.apache.org/licenses/LICENSE-2.0
 
-   Unless required by applicable law or agreed to in writing, software
 
-   distributed under the License is distributed on an "AS IS" BASIS,
 
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
-   See the License for the specific language governing permissions and
 
-   limitations under the License.
 
- =============================================================================*/
 
- #include "ctkPluginStorageSQL_p.h"
 
- #include "ctkPluginDatabaseException.h"
 
- #include "ctkPlugin.h"
 
- #include "ctkPluginConstants.h"
 
- #include "ctkPluginException.h"
 
- #include "ctkPluginArchiveSQL_p.h"
 
- #include "ctkPluginStorage_p.h"
 
- #include "ctkPluginFrameworkUtil_p.h"
 
- #include "ctkPluginFrameworkContext_p.h"
 
- #include "ctkServiceException.h"
 
- #include <QApplication>
 
- #include <QFileInfo>
 
- #include <QUrl>
 
- //database table names
 
- #define PLUGINS_TABLE "Plugins"
 
- #define PLUGIN_RESOURCES_TABLE "PluginResources"
 
- //----------------------------------------------------------------------------
 
- enum TBindIndexes
 
- {
 
-   EBindIndex=0,
 
-   EBindIndex1,
 
-   EBindIndex2,
 
-   EBindIndex3,
 
-   EBindIndex4,
 
-   EBindIndex5,
 
-   EBindIndex6,
 
-   EBindIndex7
 
- };
 
- //----------------------------------------------------------------------------
 
- ctkPluginStorageSQL::ctkPluginStorageSQL(ctkPluginFrameworkContext *framework)
 
-   : m_isDatabaseOpen(false)
 
-   , m_inTransaction(false)
 
-   , m_framework(framework)
 
-   , m_nextFreeId(-1)
 
- {
 
-   // See if we have a storage database
 
-   m_databasePath = ctkPluginFrameworkUtil::getFileStorage(framework, "").absoluteFilePath("plugins.db");
 
-   this->open();
 
-   restorePluginArchives();
 
- }
 
- //----------------------------------------------------------------------------
 
- ctkPluginStorageSQL::~ctkPluginStorageSQL()
 
- {
 
-   close();
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::open()
 
- {
 
-   if (m_isDatabaseOpen)
 
-     return;
 
-   QString path;
 
-   //Create full path to database
 
-   if(m_databasePath.isEmpty ())
 
-     m_databasePath = getDatabasePath();
 
-   path = m_databasePath;
 
-   QFileInfo dbFileInfo(path);
 
-   if (!dbFileInfo.dir().exists())
 
-   {
 
-     if(!QDir::root().mkpath(dbFileInfo.path()))
 
-     {
 
-       close();
 
-       QString errorText("Could not create database directory: %1");
 
-       throw ctkPluginDatabaseException(errorText.arg(dbFileInfo.path()), ctkPluginDatabaseException::DB_CREATE_DIR_ERROR);
 
-     }
 
-   }
 
-   m_connectionName = dbFileInfo.completeBaseName();
 
-   QSqlDatabase database;
 
-   if (QSqlDatabase::contains(m_connectionName))
 
-   {
 
-     database = QSqlDatabase::database(m_connectionName);
 
-   }
 
-   else
 
-   {
 
-     database = QSqlDatabase::addDatabase("QSQLITE", m_connectionName);
 
-     database.setDatabaseName(path);
 
-   }
 
-   if (!database.isValid())
 
-   {
 
-     close();
 
-     throw ctkPluginDatabaseException(QString("Invalid database connection: %1").arg(m_connectionName),
 
-                                   ctkPluginDatabaseException::DB_CONNECTION_INVALID);
 
-   }
 
-   //Create or open database
 
-   if (!database.isOpen())
 
-   {
 
-     if (!database.open())
 
-     {
 
-       close();
 
-       throw ctkPluginDatabaseException(QString("Could not open database. ") + database.lastError().text(),
 
-                                     ctkPluginDatabaseException::DB_SQL_ERROR);
 
-     }
 
-   }
 
-   m_isDatabaseOpen = true;
 
-   //Check if the sqlite version supports foreign key constraints
 
-   QSqlQuery query(database);
 
-   if (!query.exec("PRAGMA foreign_keys"))
 
-   {
 
-     close();
 
-     throw ctkPluginDatabaseException(QString("Check for foreign key support failed."),
 
-                                   ctkPluginDatabaseException::DB_SQL_ERROR);
 
-   }
 
-   if (!query.next())
 
-   {
 
-     close();
 
-     throw ctkPluginDatabaseException(QString("SQLite db does not support foreign keys. It is either older than 3.6.19 or was compiled with SQLITE_OMIT_FOREIGN_KEY or SQLITE_OMIT_TRIGGER"),
 
-                                   ctkPluginDatabaseException::DB_SQL_ERROR);
 
-   }
 
-   query.finish();
 
-   query.clear();
 
-   //Enable foreign key support
 
-   if (!query.exec("PRAGMA foreign_keys = ON"))
 
-   {
 
-     close();
 
-     throw ctkPluginDatabaseException(QString("Enabling foreign key support failed."),
 
-                                   ctkPluginDatabaseException::DB_SQL_ERROR);
 
-   }
 
-   query.finish();
 
-   //Check database structure (tables) and recreate tables if neccessary
 
-   //If one of the tables is missing remove all tables and recreate them
 
-   //This operation is required in order to avoid data coruption
 
-   if (!checkTables())
 
-   {
 
-     if (dropTables())
 
-     {
 
-       createTables();
 
-     }
 
-     else
 
-     {
 
-       //dropTables() should've handled error message
 
-       //and warning
 
-       close();
 
-     }
 
-   }
 
-   // silently remove any plugin marked as uninstalled
 
-   cleanupDB();
 
-   //Update database based on the recorded timestamps
 
-   updateDB();
 
-   initNextFreeIds();
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::initNextFreeIds()
 
- {
 
-   checkConnection();
 
-   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
 
-   QSqlQuery query(database);
 
-   QString statement = "SELECT ID,MAX(Generation) FROM " PLUGINS_TABLE " GROUP BY ID";
 
-   executeQuery(&query, statement);
 
-   while (query.next())
 
-   {
 
-     m_generations.insert(query.value(EBindIndex).toInt(),
 
-                          query.value(EBindIndex1).toInt()+1);
 
-   }
 
-   query.finish();
 
-   query.clear();
 
-   statement = "SELECT MAX(ID) FROM " PLUGINS_TABLE;
 
-   executeQuery(&query, statement);
 
-   QVariant id = query.next() ? query.value(EBindIndex) : QVariant();
 
-   if (id.isValid())
 
-   {
 
-     m_nextFreeId = id.toInt() + 1;
 
-   }
 
-   else
 
-   {
 
-     m_nextFreeId = 1;
 
-   }
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::cleanupDB()
 
- {
 
-   checkConnection();
 
-   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
 
-   QSqlQuery query(database);
 
-   beginTransaction(&query, Write);
 
-   try
 
-   {
 
-     // remove all plug-ins marked as UNINSTALLED
 
-     QString statement = "DELETE FROM " PLUGINS_TABLE " WHERE StartLevel==-2";
 
-     executeQuery(&query, statement);
 
-     // remove all old plug-in generations
 
-     statement = "DELETE FROM " PLUGINS_TABLE
 
-                 " WHERE K NOT IN (SELECT K FROM (SELECT K, MAX(Generation) FROM " PLUGINS_TABLE " GROUP BY ID))";
 
-   }
 
-   catch (...)
 
-   {
 
-     rollbackTransaction(&query);
 
-     throw;
 
-   }
 
-   commitTransaction(&query);
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::updateDB()
 
- {
 
-   checkConnection();
 
-   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
 
-   QSqlQuery query(database);
 
-   beginTransaction(&query, Write);
 
-   // 1. Get the state information of all plug-ins (it is assumed that
 
-   //    plug-ins marked as UNINSTALLED (startlevel == -2) are already removed
 
-   QString statement = "SELECT ID,MAX(Generation),Location,LocalPath,Timestamp,StartLevel,AutoStart,K "
 
-                       "FROM " PLUGINS_TABLE " GROUP BY ID";
 
-   QList<int> outdatedIds;
 
-   QList<QSharedPointer<ctkPluginArchiveSQL> > updatedPluginArchives;
 
-   try
 
-   {
 
-     executeQuery(&query, statement);
 
-     // 2. Check the timestamp for each plug-in
 
-     while (query.next())
 
-     {
 
-       QFileInfo pluginInfo(query.value(EBindIndex3).toString());
 
-       QDateTime pluginLastModified = pluginInfo.lastModified();
 
-       // Make sure the QDateTime has the same accuracy as the one in the database
 
-       pluginLastModified = getQDateTimeFromString(getStringFromQDateTime(pluginLastModified));
 
-       if (pluginLastModified > getQDateTimeFromString(query.value(EBindIndex4).toString()))
 
-       {
 
-         QSharedPointer<ctkPluginArchiveSQL> updatedPA(
 
-               new ctkPluginArchiveSQL(this,
 
-                                       query.value(EBindIndex2).toUrl(),    // plug-in location url
 
-                                       query.value(EBindIndex3).toString(), // plugin local path
 
-                                       query.value(EBindIndex).toInt(),     // plugin id
 
-                                       query.value(EBindIndex5).toInt(),    // start level
 
-                                       QDateTime(),                         // last modififed
 
-                                       query.value(EBindIndex6).toInt())    // auto start setting
 
-               );
 
-         updatedPA->key = query.value(EBindIndex7).toInt();
 
-         updatedPluginArchives << updatedPA;
 
-         // remember the plug-in ids for deletion
 
-         outdatedIds << query.value(EBindIndex).toInt();
 
-       }
 
-     }
 
-   }
 
-   catch (...)
 
-   {
 
-     rollbackTransaction(&query);
 
-     throw;
 
-   }
 
-   query.finish();
 
-   query.clear();
 
-   if (!outdatedIds.isEmpty())
 
-   {
 
-     // 3. Remove all traces from outdated plug-in data. Due to cascaded delete,
 
-     //    it is sufficient to remove the records from the main table
 
-     statement = "DELETE FROM " PLUGINS_TABLE " WHERE ID IN (%1)";
 
-     QString idStr;
 
-     foreach(int id, outdatedIds)
 
-     {
 
-       idStr += QString::number(id) + ",";
 
-     }
 
-     idStr.chop(1);
 
-     try
 
-     {
 
-       executeQuery(&query, statement.arg(idStr));
 
-     }
 
-     catch (...)
 
-     {
 
-       rollbackTransaction(&query);
 
-       throw;
 
-     }
 
-     query.finish();
 
-     query.clear();
 
-     try
 
-     {
 
-       foreach (QSharedPointer<ctkPluginArchiveSQL> updatedPA, updatedPluginArchives)
 
-       {
 
-         insertArchive(updatedPA, &query);
 
-       }
 
-     }
 
-     catch (...)
 
-     {
 
-       rollbackTransaction(&query);
 
-       throw;
 
-     }
 
-   }
 
-   commitTransaction(&query);
 
- }
 
- //----------------------------------------------------------------------------
 
- QLibrary::LoadHints ctkPluginStorageSQL::getPluginLoadHints() const
 
- {
 
-   if (m_framework->props.contains(ctkPluginConstants::FRAMEWORK_PLUGIN_LOAD_HINTS))
 
-   {
 
-     QVariant loadHintsVariant = m_framework->props[ctkPluginConstants::FRAMEWORK_PLUGIN_LOAD_HINTS];
 
-     if (loadHintsVariant.isValid())
 
-     {
 
-       return loadHintsVariant.value<QLibrary::LoadHints>();
 
-     }
 
-   }
 
-   return QLibrary::LoadHints(0);
 
- }
 
- //----------------------------------------------------------------------------
 
- QSharedPointer<ctkPluginArchive> ctkPluginStorageSQL::insertPlugin(const QUrl& location, const QString& localPath)
 
- {
 
-   QMutexLocker lock(&m_archivesLock);
 
-   QFileInfo fileInfo(localPath);
 
-   if (!fileInfo.exists())
 
-   {
 
-     throw std::invalid_argument((localPath + " does not exist").toStdString());
 
-   }
 
-   const QString libTimestamp = getStringFromQDateTime(fileInfo.lastModified());
 
-   QSharedPointer<ctkPluginArchiveSQL> archive(new ctkPluginArchiveSQL(this, location, localPath,
 
-                                                                       m_nextFreeId++));
 
-   try
 
-   {
 
-     insertArchive(archive);
 
-     m_archives << archive;
 
-     return archive;
 
-   }
 
-   catch(...)
 
-   {
 
-     m_nextFreeId--;
 
-     throw;
 
-   }
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::insertArchive(QSharedPointer<ctkPluginArchiveSQL> pa)
 
- {
 
-   checkConnection();
 
-   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
 
-   QSqlQuery query(database);
 
-   beginTransaction(&query, Write);
 
-   try
 
-   {
 
-     insertArchive(pa, &query);
 
-   }
 
-   catch (...)
 
-   {
 
-     rollbackTransaction(&query);
 
-     throw;
 
-   }
 
-   commitTransaction(&query);
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::insertArchive(QSharedPointer<ctkPluginArchiveSQL> pa, QSqlQuery* query)
 
- {
 
-   QFileInfo fileInfo(pa->getLibLocation());
 
-   QString libTimestamp = getStringFromQDateTime(fileInfo.lastModified());
 
-   QString resourcePrefix = fileInfo.baseName();
 
-   if (resourcePrefix.startsWith("lib"))
 
-   {
 
-     resourcePrefix = resourcePrefix.mid(3);
 
-   }
 
-   resourcePrefix.replace("_", ".");
 
-   resourcePrefix = QString(":/") + resourcePrefix + "/";
 
-   // Load the plugin and cache the resources
 
-   QPluginLoader pluginLoader;
 
-   pluginLoader.setLoadHints(getPluginLoadHints());
 
-   pluginLoader.setFileName(pa->getLibLocation());
 
-   if (!pluginLoader.load())
 
-   {
 
-     ctkPluginException exc(QString("The plugin could not be loaded: %1").arg(pa->getLibLocation()));
 
-     exc.setCause(pluginLoader.errorString());
 
-     throw exc;
 
-   }
 
-   QFile manifestResource(resourcePrefix + "META-INF/MANIFEST.MF");
 
-   manifestResource.open(QIODevice::ReadOnly);
 
-   QByteArray manifest = manifestResource.readAll();
 
-   manifestResource.close();
 
-   // Finally, complete the ctkPluginArchive information by reading the MANIFEST.MF resource
 
-   pa->readManifest(manifest);
 
-   // Assemble the data for the sql records
 
-   QString version = pa->getAttribute(ctkPluginConstants::PLUGIN_VERSION);
 
-   if (version.isEmpty()) version = "na";
 
-   QString statement = "INSERT INTO " PLUGINS_TABLE " (ID,Generation,Location,LocalPath,SymbolicName,Version,LastModified,Timestamp,StartLevel,AutoStart) "
 
-                       "VALUES (?,?,?,?,?,?,?,?,?,?)";
 
-   QList<QVariant> bindValues;
 
-   bindValues << pa->getPluginId();
 
-   bindValues << pa->getPluginGeneration();
 
-   bindValues << pa->getPluginLocation();
 
-   bindValues << pa->getLibLocation();
 
-   bindValues << pa->getAttribute(ctkPluginConstants::PLUGIN_SYMBOLICNAME);
 
-   bindValues << version;
 
-   bindValues << "na";
 
-   bindValues << libTimestamp;
 
-   bindValues << pa->getStartLevel();
 
-   bindValues << pa->getAutostartSetting();
 
-   executeQuery(query, statement, bindValues);
 
-   pa->key = query->lastInsertId().toInt();
 
-   // Write the plug-in resource data into the database
 
-   QDirIterator dirIter(resourcePrefix, QDirIterator::Subdirectories);
 
-   while (dirIter.hasNext())
 
-   {
 
-     QString resourcePath = dirIter.next();
 
-     if (QFileInfo(resourcePath).isDir()) continue;
 
-     QFile resourceFile(resourcePath);
 
-     resourceFile.open(QIODevice::ReadOnly);
 
-     QByteArray resourceData = resourceFile.readAll();
 
-     resourceFile.close();
 
-     statement = "INSERT INTO " PLUGIN_RESOURCES_TABLE " (K,ResourcePath,Resource) VALUES(?,?,?)";
 
-     bindValues.clear();
 
-     bindValues << pa->key;
 
-     bindValues << resourcePath.mid(resourcePrefix.size()-1);
 
-     bindValues << resourceData;
 
-     executeQuery(query, statement, bindValues);
 
-   }
 
-   pluginLoader.unload();
 
- }
 
- //----------------------------------------------------------------------------
 
- QSharedPointer<ctkPluginArchive> ctkPluginStorageSQL::updatePluginArchive(QSharedPointer<ctkPluginArchive> old,
 
-                                                            const QUrl& updateLocation,
 
-                                                            const QString& localPath)
 
- {
 
-   QSharedPointer<ctkPluginArchive> newPA(new ctkPluginArchiveSQL(
 
-                                            qSharedPointerCast<ctkPluginArchiveSQL>(old),
 
-                                            m_generations[old->getPluginId()]++,
 
-                                            updateLocation, localPath)
 
-                                          );
 
-   return newPA;
 
- }
 
- void ctkPluginStorageSQL::replacePluginArchive(QSharedPointer<ctkPluginArchive> oldPA, QSharedPointer<ctkPluginArchive> newPA)
 
- {
 
-   QMutexLocker lock(&m_archivesLock);
 
-   int pos;
 
-   long id = oldPA->getPluginId();
 
-   pos = find(id);
 
-   if (pos >= m_archives.size() || m_archives[pos] != oldPA)
 
-   {
 
-     throw ctkRuntimeException(QString("replacePluginArchive: Old plugin archive not found, pos=").append(pos));
 
-   }
 
-   checkConnection();
 
-   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
 
-   QSqlQuery query(database);
 
-   beginTransaction(&query, Write);
 
-   try
 
-   {
 
-     removeArchiveFromDB(static_cast<ctkPluginArchiveSQL*>(oldPA.data()), &query);
 
-     insertArchive(qSharedPointerCast<ctkPluginArchiveSQL>(newPA), &query);
 
-     commitTransaction(&query);
 
-     m_archives[pos] = newPA;
 
-   }
 
-   catch (const ctkRuntimeException& re)
 
-   {
 
-     rollbackTransaction(&query);
 
-     qWarning() << "Removing plug-in archive failed:" << re;
 
-     throw;
 
-   }
 
-   catch (...)
 
-   {
 
-     rollbackTransaction(&query);
 
-     throw;
 
-   }
 
- }
 
- //----------------------------------------------------------------------------
 
- bool ctkPluginStorageSQL::removeArchive(ctkPluginArchiveSQL* pa)
 
- {
 
-   checkConnection();
 
-   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
 
-   QSqlQuery query(database);
 
-   beginTransaction(&query, Write);
 
-   try
 
-   {
 
-     removeArchiveFromDB(pa, &query);
 
-     commitTransaction(&query);
 
-     QMutexLocker lock(&m_archivesLock);
 
-     int idx = find(pa);
 
-     if (idx >= 0 && idx < m_archives.size())
 
-     {
 
-       m_archives.removeAt(idx);
 
-     }
 
-     return true;
 
-   }
 
-   catch (const ctkRuntimeException& re)
 
-   {
 
-     rollbackTransaction(&query);
 
-     qWarning() << "Removing plug-in archive failed:" << re;
 
-   }
 
-   catch (...)
 
-   {
 
-     qWarning() << "Removing plug-in archive failed: Unexpected exception";
 
-     rollbackTransaction(&query);
 
-   }
 
-   return false;
 
- }
 
- //----------------------------------------------------------------------------
 
- bool ctkPluginStorageSQL::removeArchive(QSharedPointer<ctkPluginArchive> pa)
 
- {
 
-   return removeArchive(static_cast<ctkPluginArchiveSQL*>(pa.data()));
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::removeArchiveFromDB(ctkPluginArchiveSQL* pa, QSqlQuery* query)
 
- {
 
-   QString statement = "DELETE FROM " PLUGINS_TABLE " WHERE K=?";
 
-   QList<QVariant> bindValues;
 
-   bindValues.append(pa->key);
 
-   executeQuery(query, statement, bindValues);
 
- }
 
- QList<QSharedPointer<ctkPluginArchive> > ctkPluginStorageSQL::getAllPluginArchives() const
 
- {
 
-   return m_archives;
 
- }
 
- QList<QString> ctkPluginStorageSQL::getStartOnLaunchPlugins() const
 
- {
 
-   QList<QString> res;
 
-   foreach(QSharedPointer<ctkPluginArchive> pa, m_archives)
 
-   {
 
-     if (pa->getAutostartSetting() != -1)
 
-     {
 
-       res.push_back(pa->getPluginLocation().toString());
 
-     }
 
-   }
 
-   return res;
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::setStartLevel(int key, int startLevel)
 
- {
 
-   checkConnection();
 
-   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
 
-   QSqlQuery query(database);
 
-   QString statement = "UPDATE " PLUGINS_TABLE " SET StartLevel=? WHERE K=?";
 
-   QList<QVariant> bindValues;
 
-   bindValues.append(startLevel);
 
-   bindValues.append(key);
 
-   executeQuery(&query, statement, bindValues);
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::setLastModified(int key, const QDateTime& lastModified)
 
- {
 
-   checkConnection();
 
-   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
 
-   QSqlQuery query(database);
 
-   QString statement = "UPDATE " PLUGINS_TABLE " SET LastModified=? WHERE K=?";
 
-   QList<QVariant> bindValues;
 
-   bindValues.append(getStringFromQDateTime(lastModified));
 
-   bindValues.append(key);
 
-   executeQuery(&query, statement, bindValues);
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::setAutostartSetting(int key, int autostart)
 
- {
 
-   checkConnection();
 
-   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
 
-   QSqlQuery query(database);
 
-   QString statement = "UPDATE " PLUGINS_TABLE " SET AutoStart=? WHERE K=?";
 
-   QList<QVariant> bindValues;
 
-   bindValues.append(autostart);
 
-   bindValues.append(key);
 
-   executeQuery(&query, statement, bindValues);
 
- }
 
- //----------------------------------------------------------------------------
 
- QStringList ctkPluginStorageSQL::findResourcesPath(int archiveKey, const QString& path) const
 
- {
 
-   checkConnection();
 
-   QString statement = "SELECT SUBSTR(ResourcePath,?) FROM PluginResources WHERE K=? AND SUBSTR(ResourcePath,1,?)=?";
 
-   QString resourcePath = path.startsWith('/') ? path : QString("/") + path;
 
-   if (!resourcePath.endsWith('/'))
 
-     resourcePath += "/";
 
-   QList<QVariant> bindValues;
 
-   bindValues.append(resourcePath.size()+1);
 
-   bindValues.append(archiveKey);
 
-   bindValues.append(resourcePath.size());
 
-   bindValues.append(resourcePath);
 
-   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
 
-   QSqlQuery query(database);
 
-   executeQuery(&query, statement, bindValues);
 
-   QSet<QString> paths;
 
-   while (query.next())
 
-   {
 
-     QString currPath = query.value(EBindIndex).toString();
 
-     QStringList components = currPath.split('/', QString::SkipEmptyParts);
 
-     if (components.size() == 1)
 
-     {
 
-       paths << components.front();
 
-     }
 
-     else if (components.size() == 2)
 
-     {
 
-       paths << components.front() + "/";
 
-     }
 
-   }
 
-   return paths.toList();
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::executeQuery(QSqlQuery *query, const QString &statement, const QList<QVariant> &bindValues) const
 
- {
 
-   Q_ASSERT(query != 0);
 
-   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 = "Problem: Could not %1 statement: %2\n"
 
-               "Reason: %3\n"
 
-               "Parameters: %4\n";
 
-       QString parameters;
 
-       if (bindValues.count() > 0)
 
-       {
 
-         for (int i = 0; i < bindValues.count(); ++i)
 
-         {
 
-           parameters.append(QString("\n\t[") + QString::number(i) + "]: " + bindValues.at(i).toString());
 
-         }
 
-       }
 
-       else
 
-       {
 
-         parameters = "None";
 
-       }
 
-       ctkPluginDatabaseException::Type errorType;
 
-       int result = query->lastError().number();
 
-       if (result == 26 || result == 11) //SQLILTE_NOTADB || SQLITE_CORRUPT
 
-       {
 
-         qWarning() << "ctkPluginFramework:- Database file is corrupt or invalid:" << getDatabasePath();
 
-         errorType = ctkPluginDatabaseException::DB_FILE_INVALID;
 
-       }
 
-       else if (result == 8) //SQLITE_READONLY
 
-         errorType = ctkPluginDatabaseException::DB_WRITE_ERROR;
 
-       else
 
-         errorType = ctkPluginDatabaseException::DB_SQL_ERROR;
 
-       query->finish();
 
-       query->clear();
 
-       throw ctkPluginDatabaseException(errorText.arg(stage == Prepare ? "prepare":"execute")
 
-                   .arg(statement).arg(query->lastError().text()).arg(parameters), errorType);
 
-     }
 
-     if (stage == Prepare)
 
-     {
 
-       foreach(const QVariant &bindValue, bindValues)
 
-         query->addBindValue(bindValue);
 
-     }
 
-   }
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::close()
 
- {
 
-   if (m_isDatabaseOpen)
 
-   {
 
-     QSqlDatabase database = QSqlDatabase::database(m_connectionName, false);
 
-     if (database.isValid())
 
-     {
 
-       if(database.isOpen())
 
-       {
 
-         database.close();
 
-         m_isDatabaseOpen = false;
 
-         return;
 
-       }
 
-     }
 
-     else
 
-     {
 
-       throw ctkPluginDatabaseException(QString("Problem closing database: Invalid connection %1").arg(m_connectionName));
 
-     }
 
-   }
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::setDatabasePath(const QString &databasePath)
 
- {
 
-     m_databasePath = QDir::toNativeSeparators(databasePath);
 
- }
 
- //----------------------------------------------------------------------------
 
- QString ctkPluginStorageSQL::getDatabasePath() const
 
- {
 
-   QString path = m_databasePath;
 
-   if(path.isEmpty())
 
-   {
 
-     path = QDir::homePath() + "/ctkpluginfw/plugins.db";
 
-     qWarning() << "No database path set. Using default:" << path;
 
-   }
 
-   path = QDir::toNativeSeparators(path);
 
-   qDebug() << "Using database:" << path;
 
-   return path;
 
- }
 
- //----------------------------------------------------------------------------
 
- QByteArray ctkPluginStorageSQL::getPluginResource(int key, const QString& res) const
 
- {
 
-   checkConnection();
 
-   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
 
-   QSqlQuery query(database);
 
-   QString statement = "SELECT Resource FROM PluginResources WHERE K=? AND ResourcePath=?";
 
-   QString resourcePath = res.startsWith('/') ? res : QString("/") + res;
 
-   QList<QVariant> bindValues;
 
-   bindValues.append(key);
 
-   bindValues.append(resourcePath);
 
-   executeQuery(&query, statement, bindValues);
 
-   if (query.next())
 
-   {
 
-     return query.value(EBindIndex).toByteArray();
 
-   }
 
-   return QByteArray();
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::createTables()
 
- {
 
-     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
 
-     QSqlQuery query(database);
 
-     //Begin Transaction
 
-     beginTransaction(&query, Write);
 
-     QString statement("CREATE TABLE " PLUGINS_TABLE " ("
 
-                       "K INTEGER PRIMARY KEY,"
 
-                       "ID INTEGER NOT NULL,"
 
-                       "Generation INTEGER NOT NULL,"
 
-                       "Location TEXT NOT NULL,"
 
-                       "LocalPath TEXT NOT NULL,"
 
-                       "SymbolicName TEXT NOT NULL,"
 
-                       "Version TEXT NOT NULL,"
 
-                       "LastModified TEXT NOT NULL,"
 
-                       "Timestamp TEXT NOT NULL,"
 
-                       "StartLevel INTEGER NOT NULL,"
 
-                       "AutoStart INTEGER NOT NULL)");
 
-     try
 
-     {
 
-       executeQuery(&query, statement);
 
-     }
 
-     catch (...)
 
-     {
 
-       rollbackTransaction(&query);
 
-       throw;
 
-     }
 
-     statement = "CREATE TABLE " PLUGIN_RESOURCES_TABLE " ("
 
-                 "K INTEGER NOT NULL,"
 
-                 "ResourcePath TEXT NOT NULL,"
 
-                 "Resource BLOB NOT NULL,"
 
-                 "FOREIGN KEY(K) REFERENCES " PLUGINS_TABLE "(K) ON DELETE CASCADE)";
 
-     try
 
-     {
 
-       executeQuery(&query, statement);
 
-     }
 
-     catch (...)
 
-     {
 
-       rollbackTransaction(&query);
 
-       throw;
 
-     }
 
-     try
 
-     {
 
-       commitTransaction(&query);
 
-     }
 
-     catch (...)
 
-     {
 
-       rollbackTransaction(&query);
 
-       throw;
 
-     }
 
- }
 
- //----------------------------------------------------------------------------
 
- bool ctkPluginStorageSQL::checkTables() const
 
- {
 
-   bool bTables(false);
 
-   QStringList tables = QSqlDatabase::database(m_connectionName).tables();
 
-   if (tables.contains(PLUGINS_TABLE) &&
 
-       tables.contains(PLUGIN_RESOURCES_TABLE))
 
-   {
 
-     bTables = true;
 
-   }
 
-   return bTables;
 
- }
 
- //----------------------------------------------------------------------------
 
- bool ctkPluginStorageSQL::dropTables()
 
- {
 
-   //Execute transaction for deleting the database tables
 
-   QSqlDatabase database = QSqlDatabase::database(m_connectionName);
 
-   QSqlQuery query(database);
 
-   QStringList expectedTables;
 
-   expectedTables << PLUGINS_TABLE << PLUGIN_RESOURCES_TABLE;
 
-   if (database.tables().count() > 0)
 
-   {
 
-     beginTransaction(&query, Write);
 
-     QStringList actualTables = database.tables();
 
-     foreach(const QString expectedTable, expectedTables)
 
-     {
 
-       if (actualTables.contains(expectedTable))
 
-       {
 
-         try
 
-         {
 
-           executeQuery(&query, QString("DROP TABLE ") + expectedTable);
 
-         }
 
-         catch (...)
 
-         {
 
-           rollbackTransaction(&query);
 
-           throw;
 
-         }
 
-       }
 
-       try
 
-       {
 
-         commitTransaction(&query);
 
-       }
 
-       catch (...)
 
-       {
 
-         rollbackTransaction(&query);
 
-         throw;
 
-       }
 
-     }
 
-   }
 
-   return true;
 
- }
 
- //----------------------------------------------------------------------------
 
- bool ctkPluginStorageSQL::isOpen() const
 
- {
 
-   return m_isDatabaseOpen;
 
- }
 
- int ctkPluginStorageSQL::find(long id) const
 
- {
 
-   int lb = 0;
 
-   int ub = m_archives.size() - 1;
 
-   int x = 0;
 
-   while (lb < ub)
 
-   {
 
-     x = (lb + ub) / 2;
 
-     long xid = m_archives[x]->getPluginId();
 
-     if (id == xid)
 
-     {
 
-       return x;
 
-     }
 
-     else if (id < xid)
 
-     {
 
-       ub = x;
 
-     }
 
-     else
 
-     {
 
-       lb = x+1;
 
-     }
 
-   }
 
-   if (lb < m_archives.size() && m_archives[lb]->getPluginId() < id)
 
-   {
 
-     return lb + 1;
 
-   }
 
-   return lb;
 
- }
 
- //----------------------------------------------------------------------------
 
- int ctkPluginStorageSQL::find(ctkPluginArchive *pa) const
 
- {
 
-   for (int i = 0; i < m_archives.size(); ++i)
 
-   {
 
-     if (m_archives[i].data() == pa) return i;
 
-   }
 
-   return -1;
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::checkConnection() const
 
- {
 
-   if(!m_isDatabaseOpen)
 
-   {
 
-     throw ctkPluginDatabaseException("Database not open.", ctkPluginDatabaseException::DB_NOT_OPEN_ERROR);
 
-   }
 
-   if (!QSqlDatabase::database(m_connectionName).isValid())
 
-   {
 
-     throw ctkPluginDatabaseException(QString("Database connection invalid: %1").arg(m_connectionName),
 
-                                   ctkPluginDatabaseException::DB_CONNECTION_INVALID);
 
-   }
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::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
 
-       {
 
-         throw ctkPluginDatabaseException(QString("ctkPluginFramework: Database file is corrupt or invalid: %1").arg(getDatabasePath()),
 
-                                       ctkPluginDatabaseException::DB_FILE_INVALID);
 
-       }
 
-       else if (result == 8) //SQLITE_READONLY
 
-       {
 
-         throw ctkPluginDatabaseException(QString("ctkPluginFramework: Insufficient permissions to write to database: %1").arg(getDatabasePath()),
 
-                                       ctkPluginDatabaseException::DB_WRITE_ERROR);
 
-       }
 
-       else
 
-         throw ctkPluginDatabaseException(QString("ctkPluginFramework: ") + query->lastError().text(),
 
-                                       ctkPluginDatabaseException::DB_SQL_ERROR);
 
-   }
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::commitTransaction(QSqlQuery *query)
 
- {
 
-   Q_ASSERT(query != 0);
 
-   query->finish();
 
-   query->clear();
 
-   if (!query->exec(QLatin1String("COMMIT")))
 
-   {
 
-     throw ctkPluginDatabaseException(QString("ctkPluginFramework: ") + query->lastError().text(),
 
-                                   ctkPluginDatabaseException::DB_SQL_ERROR);
 
-   }
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::rollbackTransaction(QSqlQuery *query)
 
- {
 
-   Q_ASSERT(query !=0);
 
-   query->finish();
 
-   query->clear();
 
-   if (!query->exec(QLatin1String("ROLLBACK")))
 
-   {
 
-     throw ctkPluginDatabaseException(QString("ctkPluginFramework: ") + query->lastError().text(),
 
-                                   ctkPluginDatabaseException::DB_SQL_ERROR);
 
-   }
 
- }
 
- //----------------------------------------------------------------------------
 
- void ctkPluginStorageSQL::restorePluginArchives()
 
- {
 
-   checkConnection();
 
-   QSqlQuery query(QSqlDatabase::database(m_connectionName));
 
-   QString statement = "SELECT ID, Location, LocalPath, StartLevel, LastModified, AutoStart, K, MAX(Generation)"
 
-                       " FROM " PLUGINS_TABLE " WHERE StartLevel != -2 GROUP BY ID"
 
-                       " ORDER BY ID";
 
-   executeQuery(&query, statement);
 
-   while (query.next())
 
-   {
 
-     const long id = query.value(EBindIndex).toLongLong();
 
-     const QUrl location(query.value(EBindIndex1).toString());
 
-     const QString localPath(query.value(EBindIndex2).toString());
 
-     if (id <= 0 || location.isEmpty() || localPath.isEmpty())
 
-     {
 
-       throw ctkPluginDatabaseException(QString("Database integrity corrupted, row %1 contains empty values.").arg(id),
 
-                                     ctkPluginDatabaseException::DB_FILE_INVALID);
 
-     }
 
-     const int startLevel = query.value(EBindIndex3).toInt();
 
-     const QDateTime lastModified = getQDateTimeFromString(query.value(EBindIndex4).toString());
 
-     const int autoStart = query.value(EBindIndex5).toInt();
 
-     try
 
-     {
 
-       QSharedPointer<ctkPluginArchiveSQL> pa(new ctkPluginArchiveSQL(this, location, localPath, id,
 
-                                                                      startLevel, lastModified, autoStart));
 
-       pa->key = query.value(EBindIndex6).toInt();
 
-       pa->readManifest();
 
-       m_archives.append(pa);
 
-     }
 
-     catch (const ctkPluginException& exc)
 
-     {
 
-       qWarning() << exc;
 
-     }
 
-   }
 
- }
 
- //----------------------------------------------------------------------------
 
- QString ctkPluginStorageSQL::getStringFromQDateTime(const QDateTime& dateTime) const
 
- {
 
-   return dateTime.toString(Qt::ISODate);
 
- }
 
- //----------------------------------------------------------------------------
 
- QDateTime ctkPluginStorageSQL::getQDateTimeFromString(const QString& dateTimeString) const
 
- {
 
-   return QDateTime::fromString(dateTimeString, Qt::ISODate);
 
- }
 
 
  |