qtmobility/src/serviceframework/servicedatabase.cpp
changeset 1 2b40d63a9c3d
child 4 90517678cc4f
equal deleted inserted replaced
0:cfcbf08528c4 1:2b40d63a9c3d
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 //#define QT_SFW_SERVICEDATABASE_DEBUG
       
    43 
       
    44 #include "servicedatabase_p.h"
       
    45 #include <QDir>
       
    46 #include <QSet>
       
    47 #include "qserviceinterfacedescriptor.h"
       
    48 #include "qserviceinterfacedescriptor_p.h"
       
    49 #include <QUuid>
       
    50 #include "dberror_p.h"
       
    51 
       
    52 //database name
       
    53 #define RESOLVERDATABASE "services.db"
       
    54 
       
    55 //database table names
       
    56 #define SERVICE_TABLE "Service"
       
    57 #define INTERFACE_TABLE "Interface"
       
    58 #define DEFAULTS_TABLE "Defaults"
       
    59 #define SERVICE_PROPERTY_TABLE "ServiceProperty"
       
    60 #define INTERFACE_PROPERTY_TABLE "InterfaceProperty"
       
    61 
       
    62 //separator
       
    63 #define RESOLVERDATABASE_PATH_SEPARATOR "//"
       
    64 
       
    65 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
    66 #include <QDebug>
       
    67 #endif
       
    68 
       
    69 #define SERVICE_DESCRIPTION_KEY "DESCRIPTION"
       
    70 #ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
       
    71 #define SECURITY_TOKEN_KEY "SECURITYTOKEN"
       
    72 #endif
       
    73 #define INTERFACE_DESCRIPTION_KEY "DESCRIPTION"
       
    74 #define INTERFACE_CAPABILITY_KEY "CAPABILITIES"
       
    75 
       
    76 QTM_BEGIN_NAMESPACE
       
    77 
       
    78 enum TBindIndexes
       
    79     {
       
    80         EBindIndex=0,
       
    81         EBindIndex1,
       
    82         EBindIndex2,
       
    83         EBindIndex3,
       
    84         EBindIndex4,
       
    85         EBindIndex5,
       
    86         EBindIndex6,
       
    87         EBindIndex7
       
    88     };
       
    89 
       
    90 
       
    91 /*
       
    92    \class ServiceDatabase
       
    93    The ServiceDatabase is responsible for the management of a single
       
    94    service database.  It provides operations for:
       
    95    - opening and closing a connection with the database,
       
    96    - registering and unregistering services
       
    97    - querying for services and interfaces
       
    98    - setting and getting default interface implementations.
       
    99 */
       
   100 
       
   101 /*
       
   102     Constructor
       
   103 */
       
   104 ServiceDatabase::ServiceDatabase(void)
       
   105 :m_isDatabaseOpen(false),m_inTransaction(false)
       
   106 {
       
   107 }
       
   108 
       
   109 /*
       
   110     Destructor
       
   111 */
       
   112 ServiceDatabase::~ServiceDatabase()
       
   113 {
       
   114     close();
       
   115 }
       
   116 
       
   117 /*
       
   118     Opens the service database
       
   119     The method creates or opens database and creates tables if they are not present
       
   120     Returns true if the operation was successful, false if not.
       
   121 */
       
   122 bool ServiceDatabase::open()
       
   123 {
       
   124     if (m_isDatabaseOpen)
       
   125         return true;
       
   126 
       
   127     QString path;
       
   128 
       
   129     //Create full path to database
       
   130     if(m_databasePath.isEmpty ())
       
   131         m_databasePath = databasePath();
       
   132 
       
   133     path = m_databasePath;
       
   134     QFileInfo dbFileInfo(path);
       
   135     if (!dbFileInfo.dir().exists()) {
       
   136        if(!QDir::root().mkpath(dbFileInfo.path())) {
       
   137            QString errorText("Could not create database directory: %1");
       
   138            m_lastError.setError(DBError::CannotCreateDbDir, errorText.arg(dbFileInfo.path()));
       
   139 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   140            qWarning() << "ServiceDatabase::open():-"
       
   141                         << "Problem:" << qPrintable(m_lastError.text());
       
   142 #endif
       
   143            close();
       
   144            return false;
       
   145         }
       
   146     }
       
   147 
       
   148     m_connectionName = dbFileInfo.completeBaseName();
       
   149     QSqlDatabase  database;
       
   150     if(QSqlDatabase::contains(m_connectionName)) {
       
   151         database = QSqlDatabase::database(m_connectionName);
       
   152     } else {
       
   153         database = QSqlDatabase::addDatabase("QSQLITE", m_connectionName);
       
   154         database.setDatabaseName(path);
       
   155     }
       
   156 
       
   157     if (!database.isValid()){
       
   158         m_lastError.setError(DBError::InvalidDatabaseConnection);
       
   159         close();
       
   160         return false;
       
   161     }
       
   162 
       
   163     //Create or open database
       
   164     if (!database.isOpen()) {
       
   165         if(!database.open()) {
       
   166             m_lastError.setError(DBError::SqlError, database.lastError().text());
       
   167 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   168             qWarning() << "ServiceDatabase::open():-"
       
   169                         << "Problem:" << "Could not open database"
       
   170                         << "\nReason:" << m_lastError.text();
       
   171 #endif
       
   172             close();
       
   173             return false;
       
   174         }
       
   175     }
       
   176     m_isDatabaseOpen = true;
       
   177 
       
   178     //Check database structure (tables) and recreate tables if neccessary
       
   179     //If one of tables is missing remove all tables and recreate them
       
   180     //This operation is required in order to avoid data coruption
       
   181     if (!checkTables()) {
       
   182         if(dropTables()) {
       
   183             if (createTables()) {
       
   184 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   185                 qDebug() << "ServiceDatabase::open():-"
       
   186                     << "Database tables recreated";
       
   187 #endif
       
   188             } else {
       
   189                 //createTable() should've handled error message
       
   190                 //and warning
       
   191                 close();
       
   192                 return false;
       
   193             }
       
   194         }
       
   195         else {
       
   196             //dropTables() should've handled error message
       
   197             //and warning
       
   198             close();
       
   199             return false;
       
   200         }
       
   201     }
       
   202     return true;
       
   203 }
       
   204 
       
   205 /*
       
   206    Adds a \a service into the database.
       
   207 
       
   208    May set the following error codes
       
   209    DBError::NoError
       
   210    DBError::LocationAlreadyRegistered
       
   211    DBError::IfaceImplAlreadyRegistered
       
   212    DBError::SqlError
       
   213    DBError::DatabaseNotOpen
       
   214    DBError::InvalidDatabaseConnection
       
   215    DBError::NoWritePermissions
       
   216    DBError::InvalidDatabaseFile
       
   217 */
       
   218 //bool ServiceDatabase::registerService(ServiceMetaData &service)
       
   219 bool ServiceDatabase::registerService(const ServiceMetaDataResults &service, const QString &securityToken)
       
   220 {
       
   221 #ifndef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
       
   222     Q_UNUSED(securityToken);
       
   223 #endif
       
   224 
       
   225     if(!checkConnection()) {
       
   226 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   227         qWarning() << "ServiceDatabase::registerService():-"
       
   228                     << "Problem:" << qPrintable(m_lastError.text());
       
   229 #endif
       
   230         return false;
       
   231     }
       
   232 
       
   233     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
       
   234     QSqlQuery query(database);
       
   235 
       
   236     if (!beginTransaction(&query, Write)) {
       
   237 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   238         qWarning() << "ServiceDatabase::registerService():-"
       
   239                     << "Unable to begin transaction"
       
   240                     << "\nReason:" << qPrintable(m_lastError.text());
       
   241 #endif
       
   242         return false;
       
   243     }
       
   244     //See if the service's location has already been previously registered
       
   245     QString statement("SELECT Name from Service WHERE Location=? COLLATE NOCASE");
       
   246     QList<QVariant> bindValues;
       
   247     bindValues.append(service.location);
       
   248     if (!executeQuery(&query, statement, bindValues)) {
       
   249         rollbackTransaction(&query);
       
   250 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   251         qWarning() << "ServiceDatabase::registerService():-"
       
   252                     << qPrintable(m_lastError.text());
       
   253 #endif
       
   254         return false;
       
   255     }
       
   256 
       
   257     if (query.next()) {
       
   258         QString alreadyRegisteredService = query.value(EBindIndex).toString();
       
   259         const QString errorText = "Cannot register service \"%1\". Service location \"%2\" is already "
       
   260                     "registered to service \"%3\".  \"%3\" must first be deregistered "
       
   261                     "for new registration to take place.";
       
   262 
       
   263         m_lastError.setError(DBError::LocationAlreadyRegistered,
       
   264                 errorText.arg(service.name)
       
   265                         .arg(service.location)
       
   266                         .arg(alreadyRegisteredService));
       
   267 
       
   268         rollbackTransaction(&query);
       
   269 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   270         qWarning() << "ServiceDatabase::registerService():-"
       
   271                     << "Problem:" << qPrintable(m_lastError.text());
       
   272 #endif
       
   273         return false;
       
   274     }
       
   275 
       
   276 #ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
       
   277     statement = "SELECT Value FROM ServiceProperty WHERE ServiceID = ? AND Key = ?";
       
   278     bindValues.clear();
       
   279     bindValues.append(service.name);
       
   280     bindValues.append(SECURITY_TOKEN_KEY);
       
   281     
       
   282     if(!executeQuery(&query, statement, bindValues)) {
       
   283         rollbackTransaction(&query);
       
   284 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   285         qWarning() << "ServiceDatabase::registerService():-"
       
   286                     << qPrintable(m_lastError.text());
       
   287 #endif
       
   288         return false;
       
   289     }
       
   290 
       
   291     QStringList securityTokens;
       
   292     while(query.next()) {
       
   293         securityTokens << query.value(EBindIndex).toString();
       
   294     }
       
   295     
       
   296     if (!securityTokens.isEmpty() && securityTokens.first() != securityToken) {
       
   297         QString errorText("Access denied: \"%1\"");
       
   298              m_lastError.setError(DBError::NoWritePermissions, errorText.arg(service.name));
       
   299              rollbackTransaction(&query);
       
   300      #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   301              qWarning() << "ServiceDatabase::registerService():-"
       
   302                          << "Problem: Unable to register service"
       
   303                          << "\nReason:" << qPrintable(m_lastError.text());
       
   304      #endif    
       
   305              return false;
       
   306     }
       
   307 #endif
       
   308 
       
   309     statement = "INSERT INTO Service(ID,Name,Location) VALUES(?,?,?)";
       
   310     QString serviceID = QUuid::createUuid().toString();
       
   311 
       
   312     bindValues.clear();
       
   313     bindValues.append(serviceID);
       
   314     bindValues.append(service.name);
       
   315     bindValues.append(service.location);
       
   316 
       
   317     if (!executeQuery(&query, statement, bindValues)) {
       
   318         rollbackTransaction(&query);
       
   319 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   320         qWarning() << "ServiceDatabase::registerService():-"
       
   321                     << qPrintable(m_lastError.text());
       
   322 #endif
       
   323         return false;
       
   324     }
       
   325 
       
   326     statement = "INSERT INTO ServiceProperty(ServiceID,Key,Value) VALUES(?,?,?)";
       
   327     bindValues.clear();
       
   328     bindValues.append(serviceID);
       
   329     bindValues.append(SERVICE_DESCRIPTION_KEY);
       
   330     if (service.description.isNull())
       
   331         bindValues.append("");
       
   332     else
       
   333         bindValues.append(service.description);
       
   334 
       
   335     if (!executeQuery(&query, statement, bindValues)) {
       
   336         rollbackTransaction(&query);
       
   337 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   338         qWarning() << "ServiceDatabase::registerService():-"
       
   339                     << qPrintable(m_lastError.text());
       
   340 #endif
       
   341         return false;
       
   342     }
       
   343     
       
   344 #ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
       
   345     if (securityTokens.isEmpty()) {
       
   346         statement = "INSERT INTO ServiceProperty(ServiceID,Key,Value) VALUES(?,?,?)";
       
   347         bindValues.clear();
       
   348         bindValues.append(service.name);
       
   349         bindValues.append(SECURITY_TOKEN_KEY);
       
   350         bindValues.append(securityToken);
       
   351     
       
   352         if (!executeQuery(&query, statement, bindValues)) {
       
   353             rollbackTransaction(&query);
       
   354 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   355             qWarning() << "ServiceDatabase::registerService():-"
       
   356                         << qPrintable(m_lastError.text());
       
   357 #endif
       
   358             return false;
       
   359         }
       
   360     }
       
   361 #endif
       
   362     
       
   363     QList <QServiceInterfaceDescriptor> interfaces = service.interfaces;
       
   364     QString interfaceID;;
       
   365     foreach (const QServiceInterfaceDescriptor &interface, interfaces) {
       
   366         interfaceID = getInterfaceID(&query, interface);
       
   367         if (m_lastError.code() == DBError::NoError) {
       
   368             QString errorText;
       
   369             errorText = "Cannot register service \"%1\". \"%1\" is already registered "
       
   370                         "and implements interface \"%2\", Version \"%3.%4.\"  \"%1\" must "
       
   371                         "first be deregistered for new registration to take place.";
       
   372             m_lastError.setError(DBError::IfaceImplAlreadyRegistered,
       
   373                                 errorText.arg(interface.serviceName())
       
   374                                             .arg(interface.interfaceName())
       
   375                                             .arg(interface.majorVersion())
       
   376                                             .arg(interface.minorVersion()));
       
   377 
       
   378             rollbackTransaction(&query);
       
   379 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   380             qWarning() << "ServiceDatabase::registerService():-"
       
   381                         << "Problem:" << qPrintable(m_lastError.text());
       
   382 #endif
       
   383             return false;
       
   384         } else if (m_lastError.code() == DBError::NotFound){
       
   385             //No interface implementation already exists for the service
       
   386             //so add it
       
   387             if(!insertInterfaceData(&query, interface, serviceID)) {
       
   388                 rollbackTransaction(&query);
       
   389                 return false;
       
   390             } else {
       
   391                 continue;
       
   392             }
       
   393         } else {
       
   394             rollbackTransaction(&query);
       
   395 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   396             qWarning() << "ServiceDatabase::registerService():-"
       
   397                         << "Unable to confirm if implementation version"
       
   398                         << (QString::number(interface.majorVersion()) + "."
       
   399                            + QString::number(interface.minorVersion())).toAscii()
       
   400                         << "for interface" << interface.interfaceName()
       
   401                         << "is already registered for service "
       
   402                         << interface.serviceName()
       
   403                         << qPrintable(QString("\n") + m_lastError.text());
       
   404 #endif
       
   405             return false;
       
   406         }
       
   407     }
       
   408 
       
   409     interfaces = service.latestInterfaces;
       
   410     QServiceInterfaceDescriptor defaultInterface;
       
   411     foreach(const QServiceInterfaceDescriptor &interface, interfaces) {
       
   412         defaultInterface = interfaceDefault(interface.interfaceName(), NULL, true);
       
   413         if (m_lastError.code() == DBError::NoError
       
   414                 || m_lastError.code() == DBError::ExternalIfaceIDFound) {
       
   415             continue; //default already exists so don't do anything
       
   416         } else if (m_lastError.code() == DBError::NotFound) {
       
   417             //default does not already exist so create one
       
   418             interfaceID = getInterfaceID(&query, interface);
       
   419             if (m_lastError.code() != DBError::NoError) {
       
   420                 rollbackTransaction(&query);
       
   421 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   422                 qWarning() << "ServiceDatabase::registerService():-"
       
   423                     << "Unable to retrieve interfaceID for "
       
   424                         "interface" << interface.interfaceName()
       
   425                         <<  qPrintable(QString("\n") + m_lastError.text());
       
   426 #endif
       
   427                 return false;
       
   428             }
       
   429 
       
   430             statement = "INSERT INTO Defaults(InterfaceName, InterfaceID) VALUES(?,?)";
       
   431             bindValues.clear();
       
   432             bindValues.append(interface.interfaceName());
       
   433             bindValues.append(interfaceID);
       
   434             if (!executeQuery(&query, statement, bindValues)) {
       
   435                 rollbackTransaction(&query);
       
   436 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   437                 qWarning() << "ServiceDatabase::registerService():-"
       
   438                     << qPrintable(m_lastError.text());
       
   439 #endif
       
   440                 return false;
       
   441             }
       
   442         } else {
       
   443             rollbackTransaction(&query);
       
   444 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   445             qWarning() << "ServiceDatabase::registerService()"
       
   446                         << "Problem: Unable to confirm if interface"
       
   447                         << interface.interfaceName()
       
   448                         << "already has a default implementation";
       
   449 #endif
       
   450             return false;
       
   451         }
       
   452     }
       
   453 
       
   454     if(!commitTransaction(&query)) {
       
   455         rollbackTransaction(&query);
       
   456         return false;
       
   457     }
       
   458     m_lastError.setError(DBError::NoError);
       
   459     return true;
       
   460 }
       
   461 
       
   462 /*
       
   463     Obtains an interface ID corresponding to a given interface \a descriptor
       
   464 
       
   465     May set the following error codes:
       
   466     DBError::NoError
       
   467     DBError::NotFound
       
   468     DBError::SqlError
       
   469     DBError::DatabaseNotOpen
       
   470     DBError::InvalidDatabaseConnection
       
   471 */
       
   472 QString ServiceDatabase::getInterfaceID(const QServiceInterfaceDescriptor &descriptor) {
       
   473     QString interfaceID;
       
   474     if (!checkConnection()) {
       
   475 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   476         qWarning() << "ServiceDatabase::getInterfaceID():-"
       
   477                     << "Problem:" << qPrintable(m_lastError.text());
       
   478 #endif
       
   479         return interfaceID;
       
   480     }
       
   481 
       
   482     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
       
   483     QSqlQuery query(database);
       
   484 
       
   485     return getInterfaceID(&query, descriptor);
       
   486 }
       
   487 
       
   488 /*
       
   489     This function should only ever be called on a user scope database.
       
   490     It returns a list of Interface Name and Interface ID pairs, where
       
   491     the Interface ID refers to an external interface implementation
       
   492     in the system scope database.
       
   493 
       
   494     May set the last error to:
       
   495     DBError::NoError
       
   496     DBError::SqlError
       
   497     DBError::DatabaseNotOpen
       
   498     DBError::InvalidDatabaseConnection
       
   499 
       
   500     Aside:  There is only one query which implicitly gets
       
   501     wrapped in it's own transaction.
       
   502 */
       
   503 QList<QPair<QString,QString> > ServiceDatabase::externalDefaultsInfo()
       
   504 {
       
   505     QList<QPair<QString,QString> > ret;
       
   506     if (!checkConnection()) {
       
   507 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   508         qWarning() << "ServiceDatabase::externalDefaultsInfo():-"
       
   509                     << "Problem:" << qPrintable(m_lastError.text());
       
   510 #endif
       
   511         return ret;
       
   512     }
       
   513 
       
   514     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
       
   515     QSqlQuery query(database);
       
   516 
       
   517     //Prepare search query, bind criteria values and execute search
       
   518     QString selectComponent = "SELECT InterfaceName, InterfaceID ";
       
   519     QString fromComponent = "FROM Defaults ";
       
   520     QString whereComponent = "WHERE InterfaceID NOT IN (SELECT Interface.ID FROM Interface) ";
       
   521 
       
   522     //Aside: this individual query is implicitly wrapped in a transaction
       
   523     if (!executeQuery(&query, selectComponent + fromComponent + whereComponent)) {
       
   524 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   525         qWarning() << "ServiceDatabase::externalDefaultsInfo():-"
       
   526                     << "Problem:" << qPrintable(m_lastError.text());
       
   527 #endif
       
   528         return ret;
       
   529     }
       
   530 
       
   531     while (query.next()) {
       
   532         ret.append(qMakePair(query.value(EBindIndex).toString(),
       
   533                     query.value(EBindIndex1).toString()));
       
   534     }
       
   535 
       
   536     m_lastError.setError(DBError::NoError);
       
   537     return ret;
       
   538 }
       
   539 
       
   540 /*
       
   541     Helper function that obtains an interfaceID for a given \a descriptor.
       
   542 
       
   543     May set last error to one of the following error codes:
       
   544     DBError::NoError
       
   545     DBError::NotFound
       
   546     DBError::SqlError
       
   547 
       
   548     Aside: This function may be safely called standalone or within an explicit
       
   549     transaction.  If called standalone, it's single query is implicitly
       
   550     wrapped in it's own transaction.
       
   551 */
       
   552 QString ServiceDatabase::getInterfaceID(QSqlQuery *query, const QServiceInterfaceDescriptor &interface)
       
   553 {
       
   554     QString statement = "SELECT Interface.ID "
       
   555                         "FROM Interface, Service "
       
   556                         "WHERE Service.ID = Interface.ServiceID "
       
   557                         "AND Service.Name = ? COLLATE NOCASE "
       
   558                         "AND Interface.Name = ? COLLATE NOCASE "
       
   559                         "AND Interface.VerMaj = ? AND Interface.VerMin = ?";
       
   560     QList<QVariant> bindValues;
       
   561     bindValues.append(interface.serviceName());
       
   562     bindValues.append(interface.interfaceName());
       
   563     bindValues.append(interface.majorVersion());
       
   564     bindValues.append(interface.minorVersion());
       
   565 
       
   566     if (!executeQuery(query, statement, bindValues)) {
       
   567         return QString();
       
   568     }
       
   569 
       
   570     if (!query->next()) {
       
   571          QString errorText("No Interface Descriptor found with "
       
   572                             "\nService name: %1 "
       
   573                             "\nInterface name: %2 "
       
   574                             "\nVersion: %3.%4");
       
   575         m_lastError.setError(DBError::NotFound, errorText.arg(interface.serviceName())
       
   576                                                         .arg(interface.interfaceName())
       
   577                                                         .arg(interface.majorVersion())
       
   578                                                         .arg(interface.minorVersion()));
       
   579         return QString();
       
   580     }
       
   581 
       
   582     m_lastError.setError(DBError::NoError);
       
   583     return query->value(EBindIndex).toString();
       
   584 }
       
   585 
       
   586 /*
       
   587     Helper functions that saves \a interface related data in the Interface table
       
   588     The \a interface data is recorded as belonging to the service assocciated
       
   589     with \a serviceID.
       
   590 
       
   591     May set the last error to one of the following error codes:
       
   592     DBError::NoError
       
   593     DBError::SqlError
       
   594 
       
   595     Aside: It is already assumed that a write transaction has been started by the
       
   596     time this function is called; and this function will not rollback/commit
       
   597     the transaction.
       
   598 */
       
   599 bool ServiceDatabase::insertInterfaceData(QSqlQuery *query,const QServiceInterfaceDescriptor &interface, const QString &serviceID)
       
   600 {
       
   601     QString statement = "INSERT INTO Interface(ID, ServiceID,Name,VerMaj, VerMin) "
       
   602                         "VALUES(?,?,?,?,?)";
       
   603     QString interfaceID = QUuid::createUuid();
       
   604 
       
   605     QList<QVariant> bindValues;
       
   606     bindValues.append(interfaceID);
       
   607     bindValues.append(serviceID);
       
   608     bindValues.append(interface.interfaceName());
       
   609     bindValues.append(interface.majorVersion());
       
   610     bindValues.append(interface.minorVersion());
       
   611 
       
   612     if (!executeQuery(query, statement, bindValues)) {
       
   613 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   614         qWarning() << "ServiceDatabase::insertInterfaceData():-"
       
   615                     << qPrintable(m_lastError.text());
       
   616 #endif
       
   617         return false;
       
   618     }
       
   619 
       
   620     statement = "INSERT INTO InterfaceProperty(InterfaceID, Key, Value) VALUES(?,?,?)";
       
   621     QHash<QServiceInterfaceDescriptor::Attribute, QVariant>::const_iterator iter = interface.d->attributes.constBegin();
       
   622     bool isValidInterfaceProperty;
       
   623     QString capabilities;
       
   624     QString interfaceDescription;
       
   625     while (iter != interface.d->attributes.constEnd()) {
       
   626         isValidInterfaceProperty = true;
       
   627 
       
   628         bindValues.clear();
       
   629         bindValues.append(interfaceID);
       
   630         switch (iter.key()) {
       
   631             case (QServiceInterfaceDescriptor::Capabilities):
       
   632                 bindValues.append(INTERFACE_CAPABILITY_KEY);
       
   633                 capabilities = interface.attribute(QServiceInterfaceDescriptor::Capabilities).toStringList().join(",");
       
   634                 if (capabilities.isNull())
       
   635                     capabilities = "";
       
   636                 bindValues.append(capabilities);
       
   637                 break;
       
   638             case(QServiceInterfaceDescriptor::Location):
       
   639                 isValidInterfaceProperty = false;
       
   640                 break;
       
   641             case(QServiceInterfaceDescriptor::ServiceDescription):
       
   642                 isValidInterfaceProperty = false;
       
   643                 break;
       
   644             case(QServiceInterfaceDescriptor::InterfaceDescription):
       
   645                 bindValues.append(INTERFACE_DESCRIPTION_KEY);
       
   646                 interfaceDescription = interface.attribute(QServiceInterfaceDescriptor::InterfaceDescription).toString();
       
   647                 if (interfaceDescription.isNull())
       
   648                     interfaceDescription = "";
       
   649                 bindValues.append(interfaceDescription);
       
   650                 break;
       
   651             default:
       
   652                 isValidInterfaceProperty = false;
       
   653                 break;
       
   654         }
       
   655 
       
   656         if (isValidInterfaceProperty) {
       
   657               if (!executeQuery(query, statement, bindValues)) {
       
   658 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   659                   qWarning() << "ServiceDatabase::insertInterfaceData():-"
       
   660                                 << qPrintable(m_lastError.text());
       
   661 #endif
       
   662                   return false;
       
   663               }
       
   664         }
       
   665         ++iter;
       
   666     }
       
   667 
       
   668     //add custom attributes
       
   669     QHash<QString, QString>::const_iterator customIter = interface.d->customAttributes.constBegin();
       
   670     while(customIter!=interface.d->customAttributes.constEnd()) {
       
   671         bindValues.clear();
       
   672         bindValues.append(interfaceID);
       
   673         //to avoid key clashes use separate c_ namespace ->is this sufficient?
       
   674         bindValues.append("c_"+customIter.key());
       
   675         bindValues.append(customIter.value());
       
   676         if (!executeQuery(query, statement, bindValues)) {
       
   677 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   678             qWarning() << "ServiceDatabase::insertInterfaceData(customProps):-"
       
   679                             << qPrintable(m_lastError.text());
       
   680 #endif
       
   681             return false;
       
   682         }
       
   683         ++customIter;
       
   684     }
       
   685     m_lastError.setError(DBError::NoError);
       
   686     return true;
       
   687 }
       
   688 
       
   689 /*
       
   690     Helper function that executes the sql query specified in \a statement.
       
   691     It is assumed that the \a statement uses positional placeholders and
       
   692     corresponding parameters are placed in the list of \a bindValues.
       
   693 
       
   694     Aside: This function may be safely called standalone or within an explicit
       
   695     transaction.  If called standalone, it's single query is implicitly
       
   696     wrapped in it's own transaction.
       
   697 
       
   698     May set the last error to one of the following error codes:
       
   699     DBError::NoError
       
   700     DBError::SqlError
       
   701     DBError::NoWritePermissions
       
   702     DBError::InvalidDatabaseFile
       
   703 */
       
   704 bool ServiceDatabase::executeQuery(QSqlQuery *query, const QString &statement, const QList<QVariant> &bindValues)
       
   705 {
       
   706     Q_ASSERT(query != NULL);
       
   707 
       
   708     bool success = false;
       
   709     enum {Prepare =0 , Execute=1};
       
   710     for(int stage=Prepare; stage <= Execute; ++stage) {
       
   711         if ( stage == Prepare)
       
   712             success = query->prepare(statement);
       
   713         else // stage == Execute
       
   714             success = query->exec();
       
   715 
       
   716         if (!success) {
       
   717             QString errorText;
       
   718             errorText = "Problem: Could not %1 statement: %2"
       
   719                 "\nReason: %3"
       
   720                 "\nParameters: %4\n";
       
   721             QString parameters;
       
   722             if (bindValues.count() > 0) {
       
   723                 for(int i = 0; i < bindValues.count(); ++i) {
       
   724                     parameters.append(QString("\n\t[") + QString::number(i) + "]: " + bindValues.at(i).toString());
       
   725                 }
       
   726             } else {
       
   727                 parameters = "None";
       
   728             }
       
   729 
       
   730             DBError::ErrorCode errorType;
       
   731             int result = query->lastError().number();
       
   732             if (result == 26 || result == 11) {//SQLILTE_NOTADB || SQLITE_CORRUPT
       
   733                 qWarning() << "Service Framework:- Database file is corrupt or invalid:" << databasePath();
       
   734                 errorType = DBError::InvalidDatabaseFile;
       
   735             }
       
   736             else if ( result == 8) //SQLITE_READONLY
       
   737                 errorType = DBError::NoWritePermissions;
       
   738             else
       
   739                 errorType = DBError::SqlError;
       
   740 
       
   741             m_lastError.setError(errorType,
       
   742                     errorText
       
   743                     .arg(stage == Prepare ?"prepare":"execute")
       
   744                     .arg(statement)
       
   745                     .arg(query->lastError().text())
       
   746                     .arg(parameters));
       
   747 
       
   748             query->finish();
       
   749             query->clear();
       
   750             return false;
       
   751         }
       
   752 
       
   753         if (stage == Prepare) {
       
   754             foreach(const QVariant &bindValue, bindValues)
       
   755             query->addBindValue(bindValue);
       
   756         }
       
   757     }
       
   758 
       
   759     m_lastError.setError(DBError::NoError);
       
   760     return true;
       
   761 }
       
   762 
       
   763 /*
       
   764    Obtains a list of QServiceInterfaceDescriptors that match the constraints supplied
       
   765    by \a filter.
       
   766 
       
   767    May set last error to one of the following error codes:
       
   768    DBError::NoError
       
   769    DBError::SqlError
       
   770    DBError::DatabaseNotOpen
       
   771    DBError::InvalidDatabaseConnection
       
   772    DBError::NoWritePermissions
       
   773    DBError::InvalidDatabaseFile
       
   774 */
       
   775 QList<QServiceInterfaceDescriptor> ServiceDatabase::getInterfaces(const QServiceFilter &filter)
       
   776 {
       
   777     QList<QServiceInterfaceDescriptor> interfaces;
       
   778     if (!checkConnection()) {
       
   779 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   780         qWarning() << "ServiceDatabase::getInterfaces():-"
       
   781                     << "Problem:" << qPrintable(m_lastError.text());
       
   782 #endif
       
   783         return interfaces;
       
   784     }
       
   785 
       
   786     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
       
   787     QSqlQuery query(database);
       
   788 
       
   789     //multiple read queries are performed so wrap them
       
   790     //in a read only transaction
       
   791     if (!beginTransaction(&query, Read)) {
       
   792 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   793         qWarning() << "ServiceDatabase::getInterfaces():-"
       
   794                     << "Unable to begin transaction:"
       
   795                     << "\nReason:" << qPrintable(m_lastError.text());
       
   796 #endif
       
   797         return interfaces;
       
   798     }
       
   799 
       
   800     //Prepare search query, bind criteria values
       
   801     QString selectComponent = "SELECT Interface.Name, "
       
   802                                 "Service.Name, Interface.VerMaj, "
       
   803                                 "Interface.VerMin, "
       
   804                                 "Service.Location, "
       
   805                                 "Service.ID, "
       
   806                                 "Interface.ID ";
       
   807     QString fromComponent = "FROM Interface, Service ";
       
   808     QString whereComponent = "WHERE Service.ID = Interface.ServiceID ";
       
   809     QList<QVariant> bindValues;
       
   810 
       
   811     if (filter.serviceName().isEmpty() && filter.interfaceName().isEmpty()) {
       
   812         //do nothing, (don't add any extra constraints to the query
       
   813     } else {
       
   814 
       
   815         if (!filter.serviceName().isEmpty()) {
       
   816             whereComponent.append("AND Service.Name = ?").append(" COLLATE NOCASE ");
       
   817             bindValues.append(filter.serviceName());
       
   818         }
       
   819         if (!filter.interfaceName().isEmpty()) {
       
   820             whereComponent.append("AND Interface.Name = ?").append(" COLLATE NOCASE ");
       
   821             bindValues.append(filter.interfaceName());
       
   822             if (filter.majorVersion() >=0 && filter.minorVersion() >=0) {
       
   823                 if (filter.versionMatchRule() == QServiceFilter::ExactVersionMatch) {
       
   824                     whereComponent.append("AND Interface.VerMaj = ?").append(" AND Interface.VerMin = ? ");
       
   825                     bindValues.append(QString::number(filter.majorVersion()));
       
   826                     bindValues.append(QString::number(filter.minorVersion()));
       
   827                 }
       
   828                 else if (filter.versionMatchRule() == QServiceFilter::MinimumVersionMatch) {
       
   829                     whereComponent.append("AND ((Interface.VerMaj > ?")
       
   830                         .append(") OR Interface.VerMaj = ?").append(" AND Interface.VerMin >= ?").append(") ");
       
   831                     bindValues.append(QString::number(filter.majorVersion()));
       
   832                     bindValues.append(QString::number(filter.majorVersion()));
       
   833                     bindValues.append(QString::number(filter.minorVersion()));
       
   834                 }
       
   835             }
       
   836         }
       
   837     }
       
   838 
       
   839     if (!executeQuery(&query, selectComponent + fromComponent + whereComponent, bindValues)) {
       
   840 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   841         qWarning() << "ServiceDatabase::getInterfaces():-"
       
   842                     << "Problem:" << qPrintable(m_lastError.text());
       
   843 #endif
       
   844         rollbackTransaction(&query);
       
   845         return interfaces;
       
   846     }
       
   847 
       
   848     QServiceInterfaceDescriptor interface;
       
   849     interface.d = new QServiceInterfaceDescriptorPrivate;
       
   850     QStringList capabilities;
       
   851     QString serviceID;
       
   852     QString interfaceID;
       
   853     const QSet<QString> filterCaps = filter.capabilities().toSet();
       
   854     QSet<QString> difference;
       
   855 
       
   856     while(query.next()){
       
   857         difference.clear();
       
   858         interface.d->customAttributes.clear();
       
   859         interface.d->attributes.clear();
       
   860         interface.d->interfaceName =query.value(EBindIndex).toString();
       
   861         interface.d->serviceName = query.value(EBindIndex1).toString();
       
   862         interface.d->major = query.value(EBindIndex2).toInt();
       
   863         interface.d->minor = query.value(EBindIndex3).toInt();
       
   864 
       
   865         interface.d->attributes[QServiceInterfaceDescriptor::Location]
       
   866             = query.value(EBindIndex4).toString();
       
   867 
       
   868         serviceID = query.value(EBindIndex5).toString();
       
   869         if (!populateServiceProperties(&interface, serviceID)) {
       
   870             //populateServiceProperties should already give a warning message
       
   871             //and set the last error
       
   872             interfaces.clear();
       
   873             rollbackTransaction(&query);
       
   874             return interfaces;
       
   875         }
       
   876 
       
   877         interfaceID = query.value(EBindIndex6).toString();
       
   878         if (!populateInterfaceProperties(&interface, interfaceID)) {
       
   879             //populateInterfaceProperties should already give a warning message
       
   880             //and set the last error
       
   881             interfaces.clear();
       
   882             rollbackTransaction(&query);
       
   883             return interfaces;
       
   884         }
       
   885 
       
   886         const QSet<QString> ifaceCaps = interface.d->attributes.value(QServiceInterfaceDescriptor::Capabilities).toStringList().toSet();
       
   887         difference = ((filter.capabilityMatchRule() == QServiceFilter::MatchMinimum) ? (filterCaps-ifaceCaps) : (ifaceCaps-filterCaps));
       
   888         if (!difference.isEmpty())
       
   889             continue;
       
   890 
       
   891         //only return those interfaces that comply with set custom filters
       
   892         if (filter.customAttributes().size() > 0) {
       
   893             QSet<QString> keyDiff = filter.customAttributes().toSet();
       
   894             keyDiff.subtract(interface.d->customAttributes.uniqueKeys().toSet());
       
   895             if (keyDiff.isEmpty()) { //target descriptor has same custom keys as filter
       
   896                 bool isMatch = true;
       
   897                 const QStringList keys = filter.customAttributes();
       
   898                 for(int i = 0; i<keys.count(); i++) {
       
   899                     if (interface.d->customAttributes.value(keys[i]) !=
       
   900                             filter.customAttribute(keys[i])) {
       
   901                         isMatch = false;
       
   902                         break;
       
   903                     }
       
   904                 }
       
   905                 if (isMatch)
       
   906                     interfaces.append(interface);
       
   907             }
       
   908         } else { //no custom keys -> SQL statement ensures proper selection already
       
   909             interfaces.append(interface);
       
   910         }
       
   911     }
       
   912 
       
   913     rollbackTransaction(&query);//read-only operation so just rollback
       
   914     m_lastError.setError(DBError::NoError);
       
   915     return interfaces;
       
   916 }
       
   917 
       
   918 /*
       
   919    Obtains a QServiceInterfaceDescriptor that
       
   920    corresponds to a given \a interfaceID
       
   921 
       
   922    May set last error to one of the following error codes:
       
   923    DBError::NoError
       
   924    DBError::NotFound
       
   925    DBError::SqlError
       
   926    DBError::DatabaseNotOpen
       
   927    DBError::InvalidDatabaseConnection
       
   928    DBError::NoWritePermissions
       
   929    DBError::InvalidDatabaseFile
       
   930 */
       
   931 QServiceInterfaceDescriptor ServiceDatabase::getInterface(const QString &interfaceID)
       
   932 {
       
   933     QServiceInterfaceDescriptor interface;
       
   934     if (!checkConnection()) {
       
   935 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   936         qWarning() << "ServiceDatabase::getInterface():-"
       
   937                     << "Problem:" << qPrintable(m_lastError.text());
       
   938 #endif
       
   939         return interface;
       
   940     }
       
   941 
       
   942     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
       
   943     QSqlQuery query(database);
       
   944 
       
   945     if (!beginTransaction(&query, Read)) {
       
   946 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   947         qWarning() << "ServiceDatabase::getInterface():-"
       
   948                     << "Unable to begin transaction"
       
   949                     << "\nReason:" << qPrintable(m_lastError.text());
       
   950 #endif
       
   951         return interface;
       
   952     }
       
   953 
       
   954     QString selectComponent = "SELECT Interface.Name, "
       
   955                                 "Service.Name, Interface.VerMaj, "
       
   956                                 "Interface.VerMin, "
       
   957                                 "Service.Location, "
       
   958                                 "Service.ID ";
       
   959     QString fromComponent = "FROM Interface, Service ";
       
   960     QString whereComponent = "WHERE Service.ID = Interface.ServiceID "
       
   961                                     "AND Interface.ID = ? ";
       
   962     QList<QVariant> bindValues;
       
   963     bindValues.append(interfaceID);
       
   964 
       
   965     if (!executeQuery(&query, selectComponent + fromComponent + whereComponent, bindValues)) {
       
   966         rollbackTransaction(&query);
       
   967 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
   968         qWarning() << "ServiceDatabase::getInterfaces():-"
       
   969                     << "Problem:" << qPrintable(m_lastError.text());
       
   970 #endif
       
   971         return interface;
       
   972     }
       
   973 
       
   974     if (!query.next()) {
       
   975         rollbackTransaction(&query);
       
   976         QString errorText("Interface implementation not found for Interface ID: %1");
       
   977         m_lastError.setError(DBError::NotFound, errorText.arg(interfaceID));
       
   978         return interface;
       
   979     }
       
   980 
       
   981     interface.d = new QServiceInterfaceDescriptorPrivate;
       
   982     interface.d->interfaceName = query.value(EBindIndex).toString();
       
   983     interface.d->serviceName = query.value(EBindIndex1).toString();
       
   984     interface.d->major = query.value(EBindIndex2).toInt();
       
   985     interface.d->minor = query.value(EBindIndex3).toInt();
       
   986     interface.d->attributes[QServiceInterfaceDescriptor::Location]
       
   987         = query.value(EBindIndex4).toString();
       
   988 
       
   989     QString serviceID = query.value(EBindIndex5).toString();
       
   990     if (!populateServiceProperties(&interface, serviceID)) {
       
   991         //populateServiceProperties should already give a warning message
       
   992         //and set the last error
       
   993         rollbackTransaction(&query);
       
   994         return QServiceInterfaceDescriptor();
       
   995     }
       
   996 
       
   997     if (!populateInterfaceProperties(&interface, interfaceID)) {
       
   998         //populateInterfaceProperties should already give a warning message
       
   999         //and set the last error
       
  1000         rollbackTransaction(&query);
       
  1001         return QServiceInterfaceDescriptor();
       
  1002     }
       
  1003 
       
  1004     rollbackTransaction(&query);//read only operation so just rollback
       
  1005     m_lastError.setError(DBError::NoError);
       
  1006     return interface;
       
  1007 }
       
  1008 
       
  1009 /*
       
  1010     Obtains a list of services names.  If \a interfaceName is empty,
       
  1011     then all service names are returned.  If \a interfaceName specifies
       
  1012     an interface then the names of all services implementing that interface
       
  1013     are returned
       
  1014 
       
  1015     May set last error to one of the following error codes:
       
  1016     DBError::NoError
       
  1017     DBError::SqlError
       
  1018     DBError::DatabaseNotOpen
       
  1019     DBError::InvalidDatabaseConnection
       
  1020     DBError::NoWritePermissions
       
  1021     DBError::InvalidDatabaseFile
       
  1022 
       
  1023     Aside:  There is only one query which implicitly gets
       
  1024     wrapped in it's own transaction.
       
  1025 */
       
  1026 QStringList ServiceDatabase::getServiceNames(const QString &interfaceName)
       
  1027 {
       
  1028     QStringList services;
       
  1029     if (!checkConnection()) {
       
  1030 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1031         qWarning() << "ServiceDatabase::getServiceNames():-"
       
  1032                     << "Problem:" << qPrintable(m_lastError.text());
       
  1033 #endif
       
  1034         return services;
       
  1035     }
       
  1036     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
       
  1037     QSqlQuery query(database);
       
  1038     QString selectComponent("SELECT DISTINCT Service.Name COLLATE NOCASE ");
       
  1039     QString fromComponent;
       
  1040     QString whereComponent;
       
  1041     QList<QVariant> bindValues;
       
  1042     if (interfaceName.isEmpty()) {
       
  1043         fromComponent = "FROM Service ";
       
  1044     } else {
       
  1045         fromComponent = "FROM Interface,Service ";
       
  1046         whereComponent = "WHERE Service.ID = Interface.ServiceID AND Interface.Name = ? COLLATE NOCASE ";
       
  1047         bindValues.append(interfaceName);
       
  1048     }
       
  1049 
       
  1050     if (!executeQuery(&query, selectComponent + fromComponent + whereComponent, bindValues)) {
       
  1051 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1052         qWarning() << "ServiceDatabase::getServiceNames():-"
       
  1053                     << qPrintable(m_lastError.text());
       
  1054 #endif
       
  1055         return services;
       
  1056     }
       
  1057 
       
  1058     while( query.next()) {
       
  1059         services.append(query.value(EBindIndex).toString());
       
  1060     }
       
  1061     query.finish();
       
  1062     query.clear();
       
  1063     m_lastError.setError(DBError::NoError);
       
  1064     return services;
       
  1065 }
       
  1066 
       
  1067 /*
       
  1068     Returns a descriptor for the default interface implementation of
       
  1069     \a interfaceName.
       
  1070 
       
  1071     For user scope databases only, \a defaultInterfaceID is set if the default
       
  1072     in the user scope database refers to a interface implementation in the
       
  1073     system scope database.  In this case the descriptor will be invalid and
       
  1074     the \a defaultInterfaceID must be used to query the system scope database,
       
  1075     The last error set to DBError::ExternalIfaceIDFound
       
  1076 
       
  1077     If this function is called within a transaction, \a inTransaction
       
  1078     must be set to true.  If \a inTransaction is false, this fuction
       
  1079     will begin and end its own transaction.
       
  1080 
       
  1081     The last error may be set to one of the following error codes:
       
  1082     DBError::NoError
       
  1083     DBError::ExternalIfaceIDFound
       
  1084     DBError::SqlError
       
  1085     DBError::DatabaseNotOpen
       
  1086     DBError::InvalidDatabaseConnection
       
  1087     DBError::NoWritePermissions
       
  1088     DBError::InvalidDatabaseFile
       
  1089 */
       
  1090 QServiceInterfaceDescriptor ServiceDatabase::interfaceDefault(const QString &interfaceName, QString *defaultInterfaceID,
       
  1091                                                                     bool inTransaction)
       
  1092 {
       
  1093     QServiceInterfaceDescriptor interface;
       
  1094     if (!checkConnection())
       
  1095     {
       
  1096 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1097         qWarning() << "ServiceDatabase::interfaceDefault():-"
       
  1098                     << "Problem:" << qPrintable(m_lastError.text());
       
  1099 #endif
       
  1100         return interface;
       
  1101     }
       
  1102 
       
  1103     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
       
  1104     QSqlQuery query(database);
       
  1105 
       
  1106     if (!inTransaction && !beginTransaction(&query, Read)) {
       
  1107 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1108         qWarning() << "ServiceDatabase::interfaceDefault(QString, QString):-"
       
  1109                     << "Unable to begin transaction"
       
  1110                     << "\nReason:" << qPrintable(m_lastError.text());
       
  1111 #endif
       
  1112         return interface;
       
  1113     }
       
  1114 
       
  1115     QString statement("SELECT InterfaceID FROM Defaults WHERE InterfaceName = ? COLLATE NOCASE");
       
  1116     QList<QVariant> bindValues;
       
  1117     bindValues.append(interfaceName);
       
  1118     if(!executeQuery(&query, statement, bindValues)) {
       
  1119         if (!inTransaction)
       
  1120             rollbackTransaction(&query);
       
  1121 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1122         qWarning() << "ServiceDatabase::interfaceDefault():-"
       
  1123                     << qPrintable(m_lastError.text());
       
  1124 #endif
       
  1125         return interface;
       
  1126     }
       
  1127 
       
  1128     QString interfaceID;
       
  1129     if (!query.next())
       
  1130     {
       
  1131         if (!inTransaction)
       
  1132             rollbackTransaction(&query);
       
  1133         QString errorText("No default service found for interface: \"%1\"");
       
  1134         m_lastError.setError(DBError::NotFound, errorText.arg(interfaceName));
       
  1135         return interface;
       
  1136     }
       
  1137     else
       
  1138         interfaceID = query.value(EBindIndex).toString();
       
  1139     Q_ASSERT(!interfaceID.isEmpty());
       
  1140 
       
  1141     statement = "SELECT Interface.Name, "
       
  1142                         "Service.Name, Interface.VerMaj, "
       
  1143                         "Interface.VerMin, "
       
  1144                         "Service.Location, "
       
  1145                         "Service.ID "
       
  1146                     "FROM Service, Interface "
       
  1147                     "WHERE Service.ID = Interface.ServiceID AND Interface.ID = ?";
       
  1148     bindValues.clear();
       
  1149     bindValues.append(interfaceID);
       
  1150     if(!executeQuery(&query, statement, bindValues))
       
  1151     {
       
  1152         if (!inTransaction)
       
  1153             rollbackTransaction(&query);
       
  1154 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1155         qWarning() << "ServiceDatabase::interfaceDefault():-"
       
  1156                     << qPrintable(m_lastError.text());
       
  1157 #endif
       
  1158         return interface;
       
  1159     }
       
  1160 
       
  1161     if(!query.next()) {
       
  1162         if (!inTransaction)
       
  1163             rollbackTransaction(&query);
       
  1164         if (defaultInterfaceID != NULL )
       
  1165             *defaultInterfaceID = interfaceID;
       
  1166         m_lastError.setError(DBError::ExternalIfaceIDFound);
       
  1167         return interface;
       
  1168     }
       
  1169 
       
  1170     interface.d = new QServiceInterfaceDescriptorPrivate;
       
  1171     interface.d->interfaceName =query.value(EBindIndex).toString();
       
  1172     interface.d->serviceName = query.value(EBindIndex1).toString();
       
  1173     interface.d->major = query.value(EBindIndex2).toInt();
       
  1174     interface.d->minor = query.value(EBindIndex3).toInt();
       
  1175 
       
  1176     interface.d->attributes[QServiceInterfaceDescriptor::Location]
       
  1177         = query.value(EBindIndex4).toString();
       
  1178 
       
  1179     QString serviceID = query.value(EBindIndex5).toString();
       
  1180     if (!populateServiceProperties(&interface, serviceID)) {
       
  1181         //populateServiceProperties should already give a warning
       
  1182         //and set the last error
       
  1183         if (!inTransaction)
       
  1184             rollbackTransaction(&query);
       
  1185         return QServiceInterfaceDescriptor();
       
  1186     }
       
  1187 
       
  1188     if (!populateInterfaceProperties(&interface, interfaceID)) {
       
  1189         //populateInterfaceProperties should already give a warning
       
  1190         //and set the last error
       
  1191         if (!inTransaction)
       
  1192             rollbackTransaction(&query);
       
  1193         return QServiceInterfaceDescriptor();
       
  1194     }
       
  1195 
       
  1196     if (!inTransaction)
       
  1197         rollbackTransaction(&query); //Read only operation so just rollback
       
  1198     m_lastError.setError(DBError::NoError);
       
  1199     return interface;
       
  1200 }
       
  1201 
       
  1202 /*
       
  1203    Sets a particular service's \a interface implementation as a the default
       
  1204    implementation to look up when using the interface's name in
       
  1205    interfaceDefault().
       
  1206 
       
  1207    For a user scope database an \a externalInterfaceID can be provided
       
  1208    so that the Defaults table will contain a "link" to an interface
       
  1209    implmentation provided in the system scope database.
       
  1210 
       
  1211    May set the last error to one of the following error codes:
       
  1212    DBError::NoError
       
  1213    DBerror::NotFound
       
  1214    DBError::SqlError
       
  1215    DBError::DatabaseNotOpen
       
  1216    DBError::InvalidDatabaseConnection
       
  1217    DBError::NoWritePermissions
       
  1218    DBError::InvalidDatabaseFile
       
  1219 */
       
  1220 bool ServiceDatabase::setInterfaceDefault(const QServiceInterfaceDescriptor &interface, const QString &externalInterfaceID)
       
  1221 {
       
  1222     if(!checkConnection()) {
       
  1223 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1224         qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
       
  1225             << "Problem:" << qPrintable(m_lastError.text());
       
  1226 #endif
       
  1227         return false;
       
  1228     }
       
  1229 
       
  1230     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
       
  1231     QSqlQuery query(database);
       
  1232 
       
  1233     //Begin Transaction
       
  1234     if(!beginTransaction(&query, Write)) {
       
  1235 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1236         qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
       
  1237             << "Problem: Unable to begin transaction"
       
  1238             << "\nReason:" << qPrintable(m_lastError.text());
       
  1239 #endif
       
  1240         return false;
       
  1241     }
       
  1242 
       
  1243     QString statement;
       
  1244     QList<QVariant> bindValues;
       
  1245     QString interfaceID = externalInterfaceID;
       
  1246     if (interfaceID.isEmpty()) {
       
  1247         statement = "SELECT Interface.ID from Interface, Service "
       
  1248                 "WHERE Service.ID = Interface.ServiceID "
       
  1249                 "AND Service.Name = ? COLLATE NOCASE "
       
  1250                 "AND Interface.Name = ? COLLATE NOCASE "
       
  1251                 "AND Interface.VerMaj = ? "
       
  1252                 "AND Interface.VerMin = ? ";
       
  1253         bindValues.append(interface.serviceName());
       
  1254         bindValues.append(interface.interfaceName());
       
  1255         bindValues.append(interface.majorVersion());
       
  1256         bindValues.append(interface.minorVersion());
       
  1257 
       
  1258         if (!executeQuery(&query, statement, bindValues)) {
       
  1259             rollbackTransaction(&query);
       
  1260 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1261             qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
       
  1262                 << qPrintable(m_lastError.text());
       
  1263 #endif
       
  1264             return false;
       
  1265         }
       
  1266 
       
  1267         if(!query.next()) {
       
  1268             QString errorText;
       
  1269             errorText = "No implementation for interface: %1, Version: %2.%3 found "
       
  1270                 "for service: %4";
       
  1271             m_lastError.setNotFoundError(errorText.arg(interface.interfaceName())
       
  1272                     .arg(interface.majorVersion())
       
  1273                     .arg(interface.minorVersion())
       
  1274                     .arg(interface.serviceName()));
       
  1275 
       
  1276             rollbackTransaction(&query);
       
  1277 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1278             qWarning() << "ServiceDatbase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
       
  1279                 << "Problem: Unable to set default service"
       
  1280                     << "\nReason:" << qPrintable(m_lastError.text());
       
  1281 #endif
       
  1282             return false;
       
  1283         }
       
  1284 
       
  1285         interfaceID = query.value(EBindIndex).toString();
       
  1286         Q_ASSERT(!interfaceID.isEmpty());
       
  1287     }
       
  1288 
       
  1289     statement = "SELECT InterfaceName FROM Defaults WHERE InterfaceName = ? COLLATE NOCASE";
       
  1290     bindValues.clear();
       
  1291     bindValues.append(interface.interfaceName());
       
  1292     if (!executeQuery(&query, statement, bindValues)) {
       
  1293         rollbackTransaction(&query);
       
  1294 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1295         qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
       
  1296                     << qPrintable(m_lastError.text());
       
  1297 #endif
       
  1298         return false;
       
  1299     }
       
  1300 
       
  1301     if (query.next()) {
       
  1302         statement = "UPDATE Defaults "
       
  1303             "SET InterfaceID = ? "
       
  1304             "WHERE InterfaceName = ? COLLATE NOCASE";
       
  1305         bindValues.clear();
       
  1306         bindValues.append(interfaceID);
       
  1307         bindValues.append(interface.interfaceName());
       
  1308 
       
  1309         if (!executeQuery(&query, statement, bindValues)) {
       
  1310             rollbackTransaction(&query);
       
  1311 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1312             qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
       
  1313                 << qPrintable(m_lastError.text());
       
  1314 #endif
       
  1315             return false;
       
  1316         }
       
  1317     } else {
       
  1318         statement = "INSERT INTO Defaults(InterfaceName,InterfaceID) VALUES(?,?)";
       
  1319         bindValues.clear();
       
  1320         bindValues.append(interface.interfaceName());
       
  1321         bindValues.append(interfaceID);
       
  1322 
       
  1323         if (!executeQuery(&query, statement, bindValues)) {
       
  1324             rollbackTransaction(&query);
       
  1325 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1326             qWarning() << "ServiceDatabase::setInterfaceDefault(QServiceInterfaceDescriptor):-"
       
  1327                 << qPrintable(m_lastError.text());
       
  1328 #endif
       
  1329             return false;
       
  1330         }
       
  1331     }
       
  1332 
       
  1333     //End Transaction
       
  1334     if (!commitTransaction(&query)) {
       
  1335         rollbackTransaction(&query);
       
  1336         return false;
       
  1337     }
       
  1338     m_lastError.setError(DBError::NoError);
       
  1339     return true;
       
  1340 }
       
  1341 
       
  1342 /*
       
  1343    Removes the service with name \a serviceName.
       
  1344    If the service provides a default interface implementation, then
       
  1345    another service implementing the highest interface implementation
       
  1346    version becomes the new default(if any).  If more than one service
       
  1347    provides same the highest version number, an arbitrary choice is made
       
  1348    between them.
       
  1349 
       
  1350    May set the last error to the folowing error codes:
       
  1351    DBError::NoError
       
  1352    DBError::NotFound
       
  1353    DBError::SqlError
       
  1354    DBError::DatabaseNotOpen
       
  1355    DBError::InvalidDatabaseConnection
       
  1356    DBError::NoWritePermissions
       
  1357    DBError::InvalidDatabaseFile
       
  1358 */
       
  1359 bool ServiceDatabase::unregisterService(const QString &serviceName, const QString &securityToken)
       
  1360 {
       
  1361 #ifndef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
       
  1362     Q_UNUSED(securityToken);
       
  1363 #endif
       
  1364 
       
  1365     if (!checkConnection()) {
       
  1366 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1367         qWarning() << "ServiceDatabase::unregisterService():-"
       
  1368                     << "Problem:" << qPrintable(m_lastError.text());
       
  1369 #endif
       
  1370         return false;
       
  1371     }
       
  1372 
       
  1373     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
       
  1374     QSqlQuery query(database);
       
  1375 
       
  1376     if(!beginTransaction(&query, Write)) {
       
  1377 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1378         qWarning() << "ServiceDatabase::unregisterService():-"
       
  1379                     << "Problem: Unable to begin transaction"
       
  1380                     << "\nReason:" << qPrintable(m_lastError.text());
       
  1381 #endif
       
  1382         return false;
       
  1383     }
       
  1384         
       
  1385     QString statement("SELECT Service.ID from Service WHERE Service.Name = ? COLLATE NOCASE");
       
  1386     QList<QVariant> bindValues;
       
  1387     bindValues.append(serviceName);
       
  1388     if(!executeQuery(&query, statement, bindValues)) {
       
  1389         rollbackTransaction(&query);
       
  1390 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1391         qWarning() << "ServiceDatabase::unregisterService():-"
       
  1392                     << qPrintable(m_lastError.text());
       
  1393 #endif
       
  1394         return false;
       
  1395     }
       
  1396 
       
  1397     QStringList serviceIDs;
       
  1398     while(query.next()) {
       
  1399         serviceIDs << query.value(EBindIndex).toString();
       
  1400     }
       
  1401 
       
  1402 
       
  1403 #ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
       
  1404     statement = "SELECT Value FROM ServiceProperty WHERE ServiceID = ? AND Key = ?";
       
  1405     bindValues.clear();
       
  1406     bindValues.append(serviceName);
       
  1407     bindValues.append(SECURITY_TOKEN_KEY);
       
  1408     if(!executeQuery(&query, statement, bindValues)) {
       
  1409         rollbackTransaction(&query);
       
  1410 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1411         qWarning() << "ServiceDatabase::unregisterService():-"
       
  1412                     << qPrintable(m_lastError.text());
       
  1413 #endif
       
  1414         return false;
       
  1415     }
       
  1416 
       
  1417     QStringList securityTokens;
       
  1418     while(query.next()) {
       
  1419         securityTokens << query.value(EBindIndex).toString();
       
  1420     }
       
  1421     
       
  1422     if (!securityTokens.isEmpty() && (securityTokens.first() != securityToken)) {
       
  1423         QString errorText("Access denied: \"%1\"");
       
  1424              m_lastError.setError(DBError::NoWritePermissions, errorText.arg(serviceName));
       
  1425              rollbackTransaction(&query);
       
  1426      #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1427              qWarning() << "ServiceDatabase::unregisterService():-"
       
  1428                          << "Problem: Unable to unregister service"
       
  1429                          << "\nReason:" << qPrintable(m_lastError.text());
       
  1430      #endif    
       
  1431     }
       
  1432     
       
  1433 #endif
       
  1434     
       
  1435     statement = "SELECT Interface.ID from Interface, Service "
       
  1436                 "WHERE Interface.ServiceID = Service.ID "
       
  1437                     "AND Service.Name =? COLLATE NOCASE";
       
  1438     bindValues.clear();
       
  1439     bindValues.append(serviceName);
       
  1440     if (!executeQuery(&query, statement, bindValues)) {
       
  1441         rollbackTransaction(&query);
       
  1442 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1443         qWarning() << "ServiceDatabase::unregisterService():-"
       
  1444                     << qPrintable(m_lastError.text());
       
  1445 #endif
       
  1446         return false;
       
  1447     }
       
  1448     
       
  1449     QStringList interfaceIDs;
       
  1450     while (query.next()) {
       
  1451         interfaceIDs << query.value(EBindIndex).toString();
       
  1452     }
       
  1453 
       
  1454     if (serviceIDs.count() == 0) {
       
  1455         QString errorText("Service not found: \"%1\"");
       
  1456         m_lastError.setError(DBError::NotFound, errorText.arg(serviceName));
       
  1457         rollbackTransaction(&query);
       
  1458 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1459         qWarning() << "ServiceDatabase::unregisterService():-"
       
  1460                     << "Problem: Unable to unregister service"
       
  1461                     << "\nReason:" << qPrintable(m_lastError.text());
       
  1462 #endif
       
  1463         return false;
       
  1464     }
       
  1465 
       
  1466     statement = "SELECT Defaults.InterfaceName "
       
  1467                 "FROM Defaults, Interface, Service "
       
  1468                 "WHERE Defaults.InterfaceID = Interface.ID "
       
  1469                     "AND Interface.ServiceID = Service.ID "
       
  1470                     "AND Service.Name = ? COLLATE NOCASE";
       
  1471     bindValues.clear();
       
  1472     bindValues.append(serviceName);
       
  1473     if (!executeQuery(&query, statement, bindValues)) {
       
  1474         rollbackTransaction(&query);
       
  1475 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1476         qWarning() << "ServiceDatabase:unregisterService():-"
       
  1477                     << qPrintable(m_lastError.text());
       
  1478 #endif
       
  1479         return false;
       
  1480     }
       
  1481 
       
  1482     QStringList serviceDefaultInterfaces;
       
  1483     while(query.next()) {
       
  1484         serviceDefaultInterfaces << query.value(EBindIndex).toString();
       
  1485     }
       
  1486 
       
  1487     
       
  1488     statement = "DELETE FROM Service WHERE Service.Name = ? COLLATE NOCASE";
       
  1489     bindValues.clear();
       
  1490     bindValues.append(serviceName);
       
  1491     if (!executeQuery(&query, statement, bindValues)) {
       
  1492         rollbackTransaction(&query);
       
  1493 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1494         qWarning() << "ServiceDatabase::unregisterService():-"
       
  1495                     << qPrintable(m_lastError.text());
       
  1496 #endif
       
  1497         return false;
       
  1498     }
       
  1499 
       
  1500     statement = "DELETE FROM Interface WHERE Interface.ServiceID = ?";
       
  1501     foreach(const QString &serviceID, serviceIDs) {
       
  1502         bindValues.clear();
       
  1503         bindValues.append(serviceID);
       
  1504         if (!executeQuery(&query, statement, bindValues)) {
       
  1505             rollbackTransaction(&query);
       
  1506 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1507             qWarning() << "ServiceDatabase::unregisterService():-"
       
  1508                         << qPrintable(m_lastError.text());
       
  1509 #endif
       
  1510             return false;
       
  1511         }
       
  1512     }
       
  1513 
       
  1514 #ifndef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
       
  1515     statement = "DELETE FROM ServiceProperty WHERE ServiceID = ?";
       
  1516 #else
       
  1517     statement = "DELETE FROM ServiceProperty WHERE ServiceID = ? AND Key <> ?";
       
  1518 #endif
       
  1519 
       
  1520     
       
  1521     foreach(const QString &serviceID, serviceIDs) {
       
  1522         bindValues.clear();
       
  1523         bindValues.append(serviceID);
       
  1524 #ifdef QT_SFW_SERVICEDATABASE_USE_SECURITY_TOKEN
       
  1525         bindValues.append(SECURITY_TOKEN_KEY);
       
  1526 #endif
       
  1527         if (!executeQuery(&query, statement, bindValues)) {
       
  1528             rollbackTransaction(&query);
       
  1529 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1530             qWarning() << "ServiceDatabase::unregisterService():-"
       
  1531                         << qPrintable(m_lastError.text());
       
  1532 #endif
       
  1533             return false;
       
  1534         }
       
  1535     }
       
  1536 
       
  1537     statement = "DELETE FROM InterfaceProperty WHERE InterfaceID = ?";
       
  1538     foreach(const QString &interfaceID,  interfaceIDs) {
       
  1539         bindValues.clear();
       
  1540         bindValues.append(interfaceID);
       
  1541         if (!executeQuery(&query, statement, bindValues)) {
       
  1542             rollbackTransaction(&query);
       
  1543 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1544             qWarning() << "ServiceDatabase::unregisterService():-"
       
  1545                         << qPrintable(m_lastError.text());
       
  1546 #endif
       
  1547             return false;
       
  1548         }
       
  1549     }
       
  1550 
       
  1551     foreach(const QString &interfaceName, serviceDefaultInterfaces) {
       
  1552         statement = "SELECT ID FROM Interface WHERE Interface.Name = ? COLLATE NOCASE "
       
  1553                     "ORDER BY Interface.VerMaj DESC, Interface.VerMin DESC";
       
  1554         bindValues.clear();
       
  1555         bindValues.append(interfaceName);
       
  1556         if (!executeQuery(&query, statement, bindValues)) {
       
  1557             rollbackTransaction(&query);
       
  1558 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1559             qWarning() << "ServiceDatabase::unregisterService():-"
       
  1560                         << qPrintable(m_lastError.text());
       
  1561 #endif
       
  1562             return false;
       
  1563         }
       
  1564 
       
  1565         if(query.next()) {
       
  1566             QString newDefaultID = query.value(EBindIndex).toString();
       
  1567             statement = "UPDATE Defaults SET InterfaceID = ? WHERE InterfaceName = ? COLLATE NOCASE ";
       
  1568             bindValues.clear();
       
  1569             bindValues.append(newDefaultID);
       
  1570             bindValues.append(interfaceName);
       
  1571             if (!executeQuery(&query, statement, bindValues)) {
       
  1572                 rollbackTransaction(&query);
       
  1573 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1574                 qWarning() << "ServiceDatabase::unregisterService():-"
       
  1575                             << qPrintable(m_lastError.text());
       
  1576 #endif
       
  1577                 return false;
       
  1578             }
       
  1579         } else {
       
  1580             statement = "DELETE FROM Defaults WHERE InterfaceName = ? COLLATE NOCASE ";
       
  1581             bindValues.clear();
       
  1582             bindValues.append(interfaceName);
       
  1583             if (!executeQuery(&query, statement, bindValues)) {
       
  1584                 rollbackTransaction(&query);
       
  1585 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1586                 qWarning() << "ServiceDatabase::unregisterService():-"
       
  1587                             << qPrintable(m_lastError.text());
       
  1588 #endif
       
  1589                 return false;
       
  1590             }
       
  1591         }
       
  1592     }
       
  1593 
       
  1594     //databaseCommit
       
  1595     if (!commitTransaction(&query)) {
       
  1596         rollbackTransaction(&query);
       
  1597         return false;
       
  1598     }
       
  1599     m_lastError.setError(DBError::NoError);
       
  1600     return true;
       
  1601 }
       
  1602 
       
  1603 /*
       
  1604     Closes the database
       
  1605 
       
  1606     May set the following error codes:
       
  1607     DBError::NoError
       
  1608     DBError::InvalidDatabaseConnection
       
  1609 */
       
  1610 bool ServiceDatabase::close()
       
  1611 {
       
  1612     if(m_isDatabaseOpen) {
       
  1613         QSqlDatabase database = QSqlDatabase::database(m_connectionName, false);
       
  1614         if (database.isValid()){
       
  1615             if(database.isOpen()) {
       
  1616                 database.close();
       
  1617                 m_isDatabaseOpen = false;
       
  1618                 return true;
       
  1619             }
       
  1620         } else {
       
  1621             m_lastError.setError(DBError::InvalidDatabaseConnection);
       
  1622 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1623             qWarning() << "ServiceDatabase::close():-"
       
  1624                         << "Problem: " << qPrintable(m_lastError.text());
       
  1625 #endif
       
  1626             return false;
       
  1627         }
       
  1628     }
       
  1629     m_lastError.setError(DBError::NoError);
       
  1630     return true;
       
  1631 }
       
  1632 
       
  1633 /*
       
  1634     Sets the path of the service database to \a databasePath
       
  1635 */
       
  1636 void ServiceDatabase::setDatabasePath(const QString &databasePath)
       
  1637 {
       
  1638     m_databasePath = QDir::toNativeSeparators(databasePath);
       
  1639 }
       
  1640 
       
  1641 /*
       
  1642     Returns the path of the service database
       
  1643 */
       
  1644 QString ServiceDatabase::databasePath() const
       
  1645 {
       
  1646     QString path;
       
  1647     if(m_databasePath.isEmpty()) {
       
  1648         QSettings settings(QSettings::SystemScope, "Nokia", "Services");
       
  1649         path = settings.value("ServicesDB/Path").toString();
       
  1650         if (path.isEmpty()) {
       
  1651             path = QDir::currentPath();
       
  1652             if (path.lastIndexOf(RESOLVERDATABASE_PATH_SEPARATOR) != path.length() -1) {
       
  1653                 path.append(RESOLVERDATABASE_PATH_SEPARATOR);
       
  1654             }
       
  1655             path.append(RESOLVERDATABASE);
       
  1656         }
       
  1657         path = QDir::toNativeSeparators(path);
       
  1658     } else {
       
  1659         path = m_databasePath;
       
  1660     }
       
  1661 
       
  1662     return path;
       
  1663 }
       
  1664 
       
  1665 /*
       
  1666     Helper method that creates the database tables: Service, Interface,
       
  1667     Defaults, ServiceProperty and InterfaceProperty
       
  1668 
       
  1669     May set the last error to one of the following error codes:
       
  1670     DBError::NoError
       
  1671     DBError::SqlError
       
  1672     DBError::NoWritePermissions
       
  1673     DBError::InvalidDatabaseFile
       
  1674 */
       
  1675 bool ServiceDatabase::createTables()
       
  1676 {
       
  1677     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
       
  1678     QSqlQuery query(database);
       
  1679 
       
  1680     //Begin Transaction
       
  1681     if (!beginTransaction(&query, Write)) {
       
  1682 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1683         qWarning() << "ServiceDatabase::createTables():-"
       
  1684                     << "Unable to begin transaction"
       
  1685                     << "\nReason:" << qPrintable(m_lastError.text());
       
  1686 #endif
       
  1687         return false;
       
  1688     }
       
  1689 
       
  1690     QString statement("CREATE TABLE Service("
       
  1691                         "ID TEXT NOT NULL PRIMARY KEY UNIQUE,"
       
  1692                         "Name TEXT NOT NULL, "
       
  1693                         "Location TEXT NOT NULL)");
       
  1694     if (!executeQuery(&query, statement)) {
       
  1695         rollbackTransaction(&query);
       
  1696 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1697         qWarning() << "ServiceDatabase::createTables():-"
       
  1698                     << qPrintable(m_lastError.text());
       
  1699 #endif
       
  1700         return false;
       
  1701     }
       
  1702 
       
  1703     statement = "CREATE TABLE Interface("
       
  1704                 "ID TEXT NOT NULL PRIMARY KEY UNIQUE,"
       
  1705                 "ServiceID TEXT NOT NULL, "
       
  1706                 "Name TEXT NOT NULL, "
       
  1707                 "VerMaj INTEGER NOT NULL, "
       
  1708                 "VerMin INTEGER NOT NULL)";
       
  1709     if (!executeQuery(&query, statement)) {
       
  1710         rollbackTransaction(&query);
       
  1711 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1712         qWarning() << "ServiceDatabase::createTables():-"
       
  1713                     << qPrintable(m_lastError.text());
       
  1714 #endif
       
  1715         return false;
       
  1716     }
       
  1717 
       
  1718     statement = "CREATE TABLE Defaults("
       
  1719                 "InterfaceName TEXT PRIMARY KEY UNIQUE NOT NULL,"
       
  1720                 "InterfaceID TEXT NOT NULL)";
       
  1721     if (!executeQuery(&query, statement)) {
       
  1722         rollbackTransaction(&query);
       
  1723 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1724         qWarning() << "ServiceDatabase::createTables():-"
       
  1725                     << qPrintable(m_lastError.text());
       
  1726 #endif
       
  1727         return false;
       
  1728     }
       
  1729 
       
  1730     statement = "CREATE TABLE ServiceProperty("
       
  1731                 "ServiceID TEXT NOT NULL,"
       
  1732                 "Key TEXT NOT NULL,"
       
  1733                 "Value TEXT NOT NULL)";
       
  1734     if (!executeQuery(&query, statement)) {
       
  1735         rollbackTransaction(&query);
       
  1736 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1737         qWarning() << "ServiceDatabase::createTables():-"
       
  1738                     << qPrintable(m_lastError.text());
       
  1739 #endif
       
  1740         return false;
       
  1741     }
       
  1742 
       
  1743     statement = "CREATE TABLE InterfaceProperty("
       
  1744                 "InterfaceID TEXT NOT NULL,"
       
  1745                 "Key TEXT NOT NULL,"
       
  1746                 "Value TEXT NOT NULL)";
       
  1747 
       
  1748     if (!executeQuery(&query, statement)) {
       
  1749         rollbackTransaction(&query);
       
  1750 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1751         qWarning() << "ServiceDatabase::createTables():-"
       
  1752                     << qPrintable(m_lastError.text());
       
  1753 #endif
       
  1754         return false;
       
  1755     }
       
  1756 
       
  1757     if(!commitTransaction(&query)) {
       
  1758         rollbackTransaction(&query);
       
  1759         return false;
       
  1760     }
       
  1761     m_lastError.setError(DBError::NoError);
       
  1762     return true;
       
  1763 }
       
  1764 
       
  1765 /*!
       
  1766     Helper method that checks if the all expected tables exist in the database
       
  1767     Returns true if they all exist and false if any of them don't
       
  1768 */
       
  1769 bool ServiceDatabase::checkTables()
       
  1770 {
       
  1771     bool bTables(false);
       
  1772     QStringList tables = QSqlDatabase::database(m_connectionName).tables();
       
  1773     if (tables.contains(SERVICE_TABLE)
       
  1774         && tables.contains(INTERFACE_TABLE)
       
  1775         && tables.contains(DEFAULTS_TABLE)
       
  1776         && tables.contains(SERVICE_PROPERTY_TABLE)
       
  1777         && tables.contains(INTERFACE_PROPERTY_TABLE)){
       
  1778             bTables = true;
       
  1779     }
       
  1780     return bTables;
       
  1781 }
       
  1782 
       
  1783 /*
       
  1784    This function should only ever be used on a user scope database
       
  1785    It removes an entry from the Defaults table where the default
       
  1786    refers to an interface implementation in the system scope database.
       
  1787    The particular default that is removed is specified by
       
  1788    \a interfaceID.
       
  1789 
       
  1790    May set the last error to one of the following error codes:
       
  1791    DBError::NoError
       
  1792    DBError::IfaceIDNotExternal
       
  1793    DBError::SqlError
       
  1794    DBError::NoWritePermissions
       
  1795    DBError::InvalidDatabaseFile
       
  1796 */
       
  1797 bool ServiceDatabase::removeExternalDefaultServiceInterface(const QString &interfaceID)
       
  1798 {
       
  1799     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
       
  1800     QSqlQuery query(database);
       
  1801 
       
  1802     //begin transaction
       
  1803     if (!beginTransaction(&query, Write)) {
       
  1804 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1805         qWarning() << "ServiceDatabase::removeExternalDefaultServiceInterface():-"
       
  1806                     << "Problem: Unable to begin transaction"
       
  1807                     << "\nReason:" << qPrintable(m_lastError.text());
       
  1808 #endif
       
  1809         return false;
       
  1810     }
       
  1811 
       
  1812     QString statement("SELECT Name FROM Interface WHERE Interface.ID = ?");
       
  1813     QList<QVariant> bindValues;
       
  1814     bindValues.append(interfaceID);
       
  1815     if (!executeQuery(&query, statement, bindValues)) {
       
  1816         rollbackTransaction(&query);
       
  1817 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1818         qWarning() << "ServiceDatabase::removeDefaultServiceInterface():-"
       
  1819                     << qPrintable(m_lastError.text());
       
  1820 #endif
       
  1821         return false;
       
  1822     }
       
  1823     if (query.next()) {
       
  1824         QString interfaceName = query.value(EBindIndex).toString();
       
  1825         QString errorText("Local interface implementation exists for interface \"%1\" "
       
  1826                            "with interfaceID: \"%2\"");
       
  1827         m_lastError.setError(DBError::IfaceIDNotExternal,
       
  1828                 errorText.arg(interfaceName).arg(interfaceID));
       
  1829         rollbackTransaction(&query);
       
  1830         return false;
       
  1831     }
       
  1832 
       
  1833     statement = "DELETE FROM Defaults WHERE InterfaceID = ? COLLATE NOCASE";
       
  1834     bindValues.clear();
       
  1835     bindValues.append(interfaceID);
       
  1836     if (!executeQuery(&query, statement, bindValues)) {
       
  1837         rollbackTransaction(&query);
       
  1838 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1839         qWarning() << "ServiceDatabase::removeDefaultServiceInterface():-"
       
  1840                     << qPrintable(m_lastError.text());
       
  1841 #endif
       
  1842         return false;
       
  1843     }
       
  1844 
       
  1845     //end transaction
       
  1846     if (!commitTransaction(&query)){
       
  1847         rollbackTransaction(&query);
       
  1848         return false;
       
  1849     }
       
  1850     m_lastError.setError(DBError::NoError);
       
  1851     return true;
       
  1852 }
       
  1853 
       
  1854 /*
       
  1855     Removes all tables from the database
       
  1856 
       
  1857     In future this function may be deprecated or removed.
       
  1858 
       
  1859     May set the last error to one of the following error codes:
       
  1860     DBError::NoError
       
  1861     DBError::SqlError
       
  1862     DBError::NoWritePermissions
       
  1863     DBError::InvalidDatabaseFile
       
  1864 */
       
  1865 bool ServiceDatabase::dropTables()
       
  1866 {
       
  1867     //Execute transaction for deleting the database tables
       
  1868     QSqlDatabase database = QSqlDatabase::database(m_connectionName);
       
  1869     QSqlQuery query(database);
       
  1870     QStringList expectedTables;
       
  1871     expectedTables << SERVICE_TABLE
       
  1872                 << INTERFACE_TABLE
       
  1873                 << DEFAULTS_TABLE
       
  1874                 << SERVICE_PROPERTY_TABLE
       
  1875                 << INTERFACE_PROPERTY_TABLE;
       
  1876 
       
  1877     if (database.tables().count() > 0) {
       
  1878         if (!beginTransaction(&query, Write)) {
       
  1879 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1880             qWarning() << "ServiceDatabase::dropTables():-"
       
  1881                         << "Unable to begin transaction"
       
  1882                         << "\nReason:" << qPrintable(m_lastError.text());
       
  1883 #endif
       
  1884             return false;
       
  1885         }
       
  1886         QStringList actualTables = database.tables();
       
  1887 
       
  1888         foreach(QString expectedTable, expectedTables) {
       
  1889             if ((actualTables.contains(expectedTable))
       
  1890                 && (!executeQuery(&query, QString("DROP TABLE ") + expectedTable))) {
       
  1891                 rollbackTransaction(&query);
       
  1892 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  1893                 qWarning() << "ServiceDatabase::dropTables():-"
       
  1894                            << qPrintable(m_lastError.text());
       
  1895 #endif
       
  1896                 return false;
       
  1897             }
       
  1898         }
       
  1899         if (!commitTransaction(&query)) {
       
  1900             rollbackTransaction(&query);
       
  1901             return false;
       
  1902         }
       
  1903     }
       
  1904     m_lastError.setError(DBError::NoError);
       
  1905     return true;
       
  1906 }
       
  1907 
       
  1908 /*
       
  1909     Checks if the database is open
       
  1910 */
       
  1911 bool ServiceDatabase::isOpen() const
       
  1912 {
       
  1913   return m_isDatabaseOpen;
       
  1914 }
       
  1915 
       
  1916 /*
       
  1917    Checks the database connection.
       
  1918 
       
  1919    May set the last error to one of the following error codes:
       
  1920    DBError::DatabaseNotOpen
       
  1921    DBError::InvalidDatabaseConnection
       
  1922 */
       
  1923 bool ServiceDatabase::checkConnection()
       
  1924 {
       
  1925     if(!m_isDatabaseOpen)
       
  1926     {
       
  1927         m_lastError.setError(DBError::DatabaseNotOpen);
       
  1928         return false;
       
  1929     }
       
  1930 
       
  1931     if (!QSqlDatabase::database(m_connectionName).isValid())
       
  1932     {
       
  1933         m_lastError.setError(DBError::InvalidDatabaseConnection);
       
  1934         return false;
       
  1935     }
       
  1936 
       
  1937     return true;
       
  1938 }
       
  1939 
       
  1940 /*
       
  1941    Begins a transcaction based on the \a type which can be Read or Write.
       
  1942 
       
  1943    May set the last error to one of the following error codes:
       
  1944    DBError::NoError
       
  1945    DBError::SqlError
       
  1946    DBError::NoWritePermissions
       
  1947    DBError::InvalidDatabaseFile
       
  1948 */
       
  1949 bool ServiceDatabase::beginTransaction(QSqlQuery *query, TransactionType type)
       
  1950 {
       
  1951     bool success;
       
  1952     if (type == Read)
       
  1953         success = query->exec(QLatin1String("BEGIN"));
       
  1954     else
       
  1955         success = query->exec(QLatin1String("BEGIN IMMEDIATE"));
       
  1956 
       
  1957     if (!success) {
       
  1958         int result = query->lastError().number();
       
  1959         if (result == 26 || result == 11) {//SQLITE_NOTADB || SQLITE_CORRUPT
       
  1960             qWarning() << "Service Framework:- Database file is corrupt or invalid:" << databasePath();
       
  1961             m_lastError.setError(DBError::InvalidDatabaseFile, query->lastError().text());
       
  1962         }
       
  1963         else if (result == 8) { //SQLITE_READONLY
       
  1964             qWarning() << "Service Framework:-  Insufficient permissions to write to database:" << databasePath();
       
  1965             m_lastError.setError(DBError::NoWritePermissions, query->lastError().text());
       
  1966         }
       
  1967         else
       
  1968             m_lastError.setError(DBError::SqlError, query->lastError().text());
       
  1969         return false;
       
  1970     }
       
  1971 
       
  1972     m_lastError.setError(DBError::NoError);
       
  1973     return true;
       
  1974 }
       
  1975 
       
  1976 /*
       
  1977     Commits a transaction
       
  1978 
       
  1979     May set the last error to one of the following error codes:
       
  1980     DBError::NoError
       
  1981     DBError::SqlError
       
  1982 */
       
  1983 bool ServiceDatabase::commitTransaction(QSqlQuery *query)
       
  1984 {
       
  1985     Q_ASSERT(query != NULL);
       
  1986     query->finish();
       
  1987     query->clear();
       
  1988     if (!query->exec(QLatin1String("COMMIT"))) {
       
  1989         m_lastError.setError(DBError::SqlError, query->lastError().text());
       
  1990         return false;
       
  1991     }
       
  1992     m_lastError.setError(DBError::NoError);
       
  1993     return true;
       
  1994 }
       
  1995 
       
  1996 /*
       
  1997     Rolls back a transaction
       
  1998 
       
  1999     May set the last error to one of the following error codes:
       
  2000     DBError::NoError
       
  2001     DBError::SqlError
       
  2002 */
       
  2003 bool ServiceDatabase::rollbackTransaction(QSqlQuery *query)
       
  2004 {
       
  2005     Q_ASSERT(query !=NULL);
       
  2006     query->finish();
       
  2007     query->clear();
       
  2008 
       
  2009     if (!query->exec(QLatin1String("ROLLBACK"))) {
       
  2010         m_lastError.setError(DBError::SqlError, query->lastError().text());
       
  2011         return false;
       
  2012     }
       
  2013     return true;
       
  2014 }
       
  2015 
       
  2016 /*
       
  2017     Helper function that populates a service \a interface descriptor
       
  2018     with interface related attributes corresponding to the interface
       
  2019     represented by \a interfaceID
       
  2020 
       
  2021     It is already assumed that a transaction has been started by the time
       
  2022     this function is called.  This function will not rollback/commit the
       
  2023     transaction.
       
  2024 
       
  2025     May set the last error to one of the following error codes:
       
  2026     DBError::NoError
       
  2027     DBError::SqlError
       
  2028 */
       
  2029 bool ServiceDatabase::populateInterfaceProperties(QServiceInterfaceDescriptor *interface, const QString &interfaceID)
       
  2030 {
       
  2031     QSqlQuery query(QSqlDatabase::database(m_connectionName));
       
  2032     QString statement("SELECT Key, Value FROM InterfaceProperty WHERE InterfaceID = ?");
       
  2033     QList<QVariant> bindValues;
       
  2034     bindValues.append(interfaceID);
       
  2035     if (!executeQuery(&query, statement, bindValues)) {
       
  2036 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  2037         qWarning() << "ServiceDatabase::populateInterfaceProperties():-"
       
  2038                     << qPrintable(m_lastError.text());
       
  2039 #endif
       
  2040         return false;
       
  2041     }
       
  2042 
       
  2043     bool isFound = false;
       
  2044     QString attribute;
       
  2045     while (query.next()) {
       
  2046         isFound = true;
       
  2047         attribute = query.value(EBindIndex).toString();
       
  2048         if (attribute == INTERFACE_CAPABILITY_KEY) {
       
  2049             const QStringList capabilities = query.value(EBindIndex1).toString().split(",");
       
  2050             if (capabilities.count() == 1 && capabilities[0].isEmpty()) {
       
  2051                 interface->d->attributes[QServiceInterfaceDescriptor::Capabilities]
       
  2052                     = QStringList();
       
  2053             } else {
       
  2054                 interface->d->attributes[QServiceInterfaceDescriptor::Capabilities]
       
  2055                 = capabilities;
       
  2056             }
       
  2057         } else if (attribute == INTERFACE_DESCRIPTION_KEY) {
       
  2058             interface->d->attributes[QServiceInterfaceDescriptor::InterfaceDescription]
       
  2059                = query.value(EBindIndex1).toString();
       
  2060         } else if (attribute.startsWith("c_")) {
       
  2061             interface->d->customAttributes[attribute.mid(2)]
       
  2062                = query.value(EBindIndex1).toString();
       
  2063         }
       
  2064     }
       
  2065 
       
  2066     if (!isFound) {
       
  2067         QString errorText("Database integrity corrupted, Properties for InterfaceID: %1 does not exist in the InterfaceProperty table for interface \"%2\"");
       
  2068         m_lastError.setError(DBError::SqlError, errorText.arg(interfaceID).arg(interface->interfaceName()));
       
  2069 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  2070         qWarning() << "ServiceDatabase::populateInterfaceProperties():-"
       
  2071                     << "Problem:" << qPrintable(m_lastError.text());
       
  2072 #endif
       
  2073         return false;
       
  2074     }
       
  2075     m_lastError.setError(DBError::NoError);
       
  2076     return true;
       
  2077 }
       
  2078 
       
  2079 /*
       
  2080     Helper function that populates a service \a interface descriptor
       
  2081     with service related attributes corresponding to the service
       
  2082     represented by \a serviceID
       
  2083 
       
  2084     It is already assumed that a transaction has been started by the time
       
  2085     this function is called.  This function will not rollback/commit the
       
  2086     transaction.
       
  2087 
       
  2088     May set the last error to one of the following error codes:
       
  2089     DBError::NoError
       
  2090     DBError::SqlError
       
  2091 */
       
  2092 bool ServiceDatabase::populateServiceProperties(QServiceInterfaceDescriptor *interface, const QString &serviceID)
       
  2093 {
       
  2094     QSqlQuery query(QSqlDatabase::database(m_connectionName));
       
  2095     QString statement("SELECT Key, Value FROM ServiceProperty WHERE ServiceID = ?");
       
  2096     QList<QVariant> bindValues;
       
  2097     bindValues.append(serviceID);
       
  2098     if (!executeQuery(&query, statement, bindValues)) {
       
  2099 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  2100         qWarning() << "ServiceDatabase::populateServiceProperties():-"
       
  2101                     << qPrintable(m_lastError.text());
       
  2102 #endif
       
  2103         return false;
       
  2104     }
       
  2105 
       
  2106     bool isFound = false;
       
  2107     QString attribute;
       
  2108     while (query.next()) {
       
  2109         isFound = true;
       
  2110         attribute = query.value(EBindIndex).toString();
       
  2111         if (attribute == SERVICE_DESCRIPTION_KEY) {
       
  2112                 interface->d->attributes[QServiceInterfaceDescriptor::ServiceDescription]
       
  2113                     = query.value(EBindIndex1).toString();
       
  2114         }
       
  2115     }
       
  2116 
       
  2117     if (!isFound) {
       
  2118         QString errorText("Database integrity corrupted, Service Properties for ServiceID: \"%1\" does not exist in the ServiceProperty table for service \"%2\"");
       
  2119         m_lastError.setError(DBError::SqlError, errorText.arg(serviceID).arg(interface->serviceName()));
       
  2120 #ifdef QT_SFW_SERVICEDATABASE_DEBUG
       
  2121         qWarning() << "ServiceDatabase::populateServiceProperties():-"
       
  2122                     << "Problem:" << qPrintable(m_lastError.text());
       
  2123 #endif
       
  2124         return false;
       
  2125     }
       
  2126     m_lastError.setError(DBError::NoError);
       
  2127     return true;
       
  2128 }
       
  2129 
       
  2130 #include "moc_servicedatabase_p.cpp"
       
  2131 
       
  2132 QTM_END_NAMESPACE