tools/servicedbgen/servicedbgen.cpp
changeset 0 876b1a06bc25
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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 #include <QtPlugin>
       
    43 
       
    44 #include <stdio.h>
       
    45 #include <QtCore>
       
    46 #include <QtSql>
       
    47 #include <servicedatabase_p.h>
       
    48 #include <servicemetadata_p.h>
       
    49 #include <databasemanager_p.h>
       
    50 
       
    51 QT_USE_NAMESPACE
       
    52 
       
    53 QTM_USE_NAMESPACE
       
    54 /*
       
    55  * If the emulator supports per process writeable static
       
    56  * data then we can use a separate server process and
       
    57  * put the db in the same location as on a real
       
    58  * device
       
    59  */
       
    60 #define WINSCW_DES_DEPLOY_WSD   "epoc32/winscw/c/private/2002AC7F/des"
       
    61 #define WINSCW_DBPATH_WSD       "epoc32/winscw/c/private/2002AC7F"
       
    62 
       
    63 #define WINSCW_DES_DEPLOY       "epoc32/winscw/c/private/2002AC7F/des"
       
    64 #define WINSCW_DBPATH           "epoc32/winscw/c/data/temp/QtServiceFW"
       
    65 
       
    66 #define HW_DES_DEPLOY           "epoc32/data/z/private/2002AC7F/des"
       
    67 #define HW_DBPATH               "epoc32/data/z/private/2002AC7F"
       
    68 
       
    69 #define SEC_TOKEN               0x101FB657
       
    70 #define TOOL_VERSION            "0.4"
       
    71 
       
    72 #define MESSAGE(msg) \
       
    73 { \
       
    74    *stdoutStream << msg; \
       
    75    stdoutStream->flush(); \
       
    76 }
       
    77 
       
    78 QString dbName()
       
    79 {
       
    80     QString qtVersion(qVersion());
       
    81     qtVersion = qtVersion.left(qtVersion.size() -2); //strip off patch version
       
    82     return QString("QtServiceFramework_") + qtVersion + "_system";
       
    83 };
       
    84 
       
    85 class GeneratorPaths
       
    86 {
       
    87 public:
       
    88     GeneratorPaths(){};
       
    89     GeneratorPaths(const QString &dbPath, const QString &desPath) : databasePath(dbPath), descriptorsPath(desPath){};
       
    90     ~GeneratorPaths(){};
       
    91     GeneratorPaths(const GeneratorPaths &copy){databasePath = copy.databasePath; descriptorsPath = copy.descriptorsPath;};
       
    92 public:
       
    93     QString databasePath;
       
    94     QString descriptorsPath;
       
    95 };
       
    96 
       
    97 class CommandProcessor : public QObject
       
    98 {
       
    99     Q_OBJECT
       
   100 
       
   101 public:
       
   102     CommandProcessor(QObject *parent = 0);
       
   103     ~CommandProcessor();
       
   104 
       
   105     bool initialize();
       
   106     void execute(const QStringList &options, const QString &cmd, const QStringList &args);
       
   107     void showUsage();
       
   108 
       
   109 public slots:
       
   110     void add(const QStringList &desList, ServiceDatabase *db);
       
   111     void remove(const QStringList &desList, ServiceDatabase *db);
       
   112 
       
   113 private:
       
   114     bool setOptions(const QStringList &options, QMap<QString, GeneratorPaths> &targets);
       
   115     ServiceDatabase *initTargetDatabase(const QString &dbPath, bool deleteDbAllowed);
       
   116     QString getServiceFromXML(const QString &xmlFile);
       
   117     QStringList getServiceDescriptors(const QString &path);
       
   118     QStringList targetServiceDescriptors(const QString &desPath, const QStringList &args);
       
   119 
       
   120     bool batchMode;
       
   121     bool requireInitialization;
       
   122     bool deleteDatabase;
       
   123     QTextStream *stdoutStream;
       
   124     QMap<QString, QString> targetMap; // (target, platform)
       
   125     QMap<QString, GeneratorPaths> pathMap; // (platform, (databasePath, descriptorsPath))
       
   126     QMap<QString, GeneratorPaths> wsdMap; // (platform, (databasePath, descriptorsPath))
       
   127 };
       
   128 
       
   129 CommandProcessor::CommandProcessor(QObject *parent)
       
   130     : QObject(parent),
       
   131       batchMode(false),
       
   132       requireInitialization(false),
       
   133       deleteDatabase(false),
       
   134       stdoutStream(new QTextStream(stdout))
       
   135 {
       
   136 }
       
   137 
       
   138 CommandProcessor::~CommandProcessor()
       
   139 {
       
   140     delete stdoutStream;
       
   141 }
       
   142 
       
   143 bool CommandProcessor::initialize()
       
   144 {
       
   145     QString epocRoot(qgetenv("EPOCROOT").data());
       
   146     if (epocRoot.isEmpty()) {
       
   147         *stdoutStream << "ERROR: EPOCROOT not set\n";
       
   148         return false;
       
   149     }
       
   150 
       
   151     targetMap["winscw"] = "emulator";
       
   152     targetMap["armv5"] = "hw";
       
   153     targetMap["armv6"] = "hw";
       
   154     targetMap["gcce"] = "hw";
       
   155 
       
   156     if (epocRoot.right(1) != QDir::separator())
       
   157         epocRoot += QDir::separator();
       
   158 
       
   159     wsdMap["nowsd"] = GeneratorPaths(QDir::toNativeSeparators(epocRoot + WINSCW_DBPATH),
       
   160                                      QDir::toNativeSeparators(epocRoot + WINSCW_DES_DEPLOY));
       
   161 
       
   162     wsdMap["wsd"] = GeneratorPaths(QDir::toNativeSeparators(epocRoot + WINSCW_DBPATH_WSD),
       
   163                                    QDir::toNativeSeparators(epocRoot + WINSCW_DES_DEPLOY_WSD));
       
   164 
       
   165 #ifdef QT_SYMBIAN_EMULATOR_SUPPORTS_PERPROCESS_WSD
       
   166     pathMap["emulator"] = wsdMap["wsd"];
       
   167 #else
       
   168     pathMap["emulator"] = wsdMap["nowsd"];
       
   169 #endif
       
   170     pathMap["hw"] = GeneratorPaths(QDir::toNativeSeparators(epocRoot + HW_DBPATH),
       
   171                                    QDir::toNativeSeparators(epocRoot + HW_DES_DEPLOY));
       
   172     return true;
       
   173 }
       
   174 
       
   175 void CommandProcessor::execute(const QStringList &options, const QString &cmd, const QStringList &args)
       
   176 {
       
   177     if(cmd.isEmpty())
       
   178         MESSAGE("Error: no command given\n\n");
       
   179 
       
   180     // setup options and collect target(s)
       
   181     // parse options, and fails if there's no cmd
       
   182     // usage output includes paths and targets, so make
       
   183     // sure to parse options that might change them
       
   184     QMap<QString, GeneratorPaths> targets;
       
   185     if (!setOptions(options, targets) || cmd.isEmpty()) {
       
   186         showUsage();
       
   187         return;
       
   188     }
       
   189 
       
   190     int methodIndex = metaObject()->indexOfMethod(cmd.toAscii() + "(QStringList,ServiceDatabase*)");
       
   191     if (methodIndex < 0) {
       
   192         MESSAGE("Bad command: " << cmd << "\n\n");
       
   193         showUsage();
       
   194         return;
       
   195     }
       
   196 
       
   197     QMapIterator<QString, GeneratorPaths> i(targets);
       
   198     while (i.hasNext()) {
       
   199         i.next();
       
   200         const QString &target = i.key();
       
   201         const GeneratorPaths &paths = i.value();
       
   202         ServiceDatabase *db = initTargetDatabase(paths.databasePath, true);
       
   203         if (!db) {
       
   204             MESSAGE("ERROR: database for " << target << " cannot be opened/created.\n");
       
   205             continue;
       
   206         }
       
   207         MESSAGE("Database[" << i.key() << "]: " << db->databasePath() << '\n');
       
   208         QStringList desList = (batchMode) ? targetServiceDescriptors(paths.descriptorsPath, args) : args;
       
   209         // register services
       
   210         metaObject()->method(methodIndex).invoke(this, Q_ARG(QStringList, desList), Q_ARG(ServiceDatabase*, db));
       
   211         // remove database so other targets can be handled
       
   212         db->close();
       
   213         QSqlDatabase::removeDatabase(db->m_connectionName);
       
   214         delete db;
       
   215     }
       
   216 }
       
   217 
       
   218 void CommandProcessor::showUsage()
       
   219 {
       
   220     *stdoutStream << "Service framework database management tool, version " << QString(TOOL_VERSION) << "\n"
       
   221             "Usage: servicedbgen [options] <command> [command parameters]\n\n"
       
   222             "Commands:\n"
       
   223             "\tadd     Register or update a service\n"
       
   224             "\tremove  Unregister a service\n"
       
   225             "\nOptions:\n"
       
   226             "\t-t<tgt> Specifies the target platform to be used (e.g. armv5, all).\n"
       
   227             "\t-b      Batch mode (take service descriptors from a path). If specified, \n"
       
   228             "\t        the command parameters are specifying the path to the folder\n"
       
   229             "\t        where the service descriptors reside. In case command parameters\n"
       
   230             "\t        are not given, the target specific default path will be taken\n"
       
   231             "\t        (see paths below).\n"
       
   232             "\t-c      Delete the service database, has effect only in batch mode. \n"
       
   233             "\t-i      The services require initialization upon first load.\n"
       
   234             "\t-w<1|0> Override the default support for WSD in the emulator\n"
       
   235             "\n"
       
   236             "Supported targets and their database paths:";
       
   237     QMapIterator<QString, QString> i(targetMap);
       
   238     while (i.hasNext()) {
       
   239         i.next();
       
   240         GeneratorPaths out(pathMap[i.value()]);
       
   241         *stdoutStream << "\nTarget: " << i.key() << "\n\tpath: " << out.databasePath << "\n\tdeployment: " << out.descriptorsPath << '\n';
       
   242     }
       
   243     *stdoutStream << "\nExamples:\n"
       
   244         " - registering service1 and service2 for winscw target:\n"
       
   245         "\tservicedbgen -twinscw add service1.xml service2.xml\n\n"
       
   246         " - registering service1 for all targets, service requesting initialization:\n"
       
   247         "\tservicedbgen -tall -i add service1.xml\n\n"
       
   248         " - unregistering service1 from all targets:\n"
       
   249         "\tservicedbgen -tall remove service1.xml\n\n"
       
   250         " - registering all services for armv5 from default descriptor path:\n"
       
   251         "\tservicedbgen -tall -b -c add\n\n"
       
   252         " - registering services for all targets from specific descriptor path:\n"
       
   253         "\tservicedbgen -tall -b add ./mypath/services\n\n"
       
   254         " - removing services for all targets from default descriptor path:\n"
       
   255         "\tservicedbgen -tall -b remove\n\n";
       
   256     stdoutStream->flush();
       
   257 }
       
   258 
       
   259 bool CommandProcessor::setOptions(const QStringList &options, QMap<QString, GeneratorPaths> &targets)
       
   260 {
       
   261     QStringList opts = options;
       
   262     QMutableListIterator<QString> i(opts);
       
   263 
       
   264     while (i.hasNext()) {
       
   265         QString option = i.next();
       
   266         if (option == "-b") {
       
   267             batchMode = true;
       
   268             i.remove();
       
   269         }
       
   270         else if (option == "-c") {
       
   271             deleteDatabase = true;
       
   272             i.remove();
       
   273         }
       
   274         else if (option == "-i") {
       
   275             requireInitialization = true;
       
   276             i.remove();
       
   277         }
       
   278         else if (option.startsWith("-t")) {
       
   279             QString target = option.right(option.size() - 2).toLower();
       
   280             if (target == "all") {
       
   281                 // copy all target paths
       
   282                 targets.clear();
       
   283                 targets = pathMap;
       
   284             }
       
   285             else if (targetMap[target].isEmpty()) {
       
   286                 MESSAGE("ERROR: unknown target " << target << '\n');
       
   287                 return false;
       
   288             }
       
   289             else if (!targets.contains(targetMap[target])){
       
   290                 targets[targetMap[target]] = pathMap[targetMap[target]];
       
   291             }
       
   292             i.remove();
       
   293         }
       
   294         else if (option.startsWith("-w")) {
       
   295             QString wsd = option.right(option.size() - 2).toLower();
       
   296             if (wsd == "0") {
       
   297                 pathMap["emulator"] = wsdMap["nowsd"];
       
   298             }
       
   299             else if (wsd == "1"){
       
   300                 pathMap["emulator"] = wsdMap["wsd"];
       
   301             }
       
   302             else {
       
   303                 MESSAGE("ERROR: unknown parameter " << wsd << '\n');
       
   304                 return false;
       
   305             }
       
   306             if(targets.contains("emulator"))
       
   307                 targets["emulator"] = pathMap["emulator"];
       
   308             i.remove();
       
   309         }
       
   310     }
       
   311     if (!opts.isEmpty()) {
       
   312         MESSAGE("Bad options: " << opts.join(" ") << "\n\n");
       
   313         return false;
       
   314     }
       
   315     if (targets.isEmpty()) {
       
   316         MESSAGE("No options\n");
       
   317         targets = pathMap;
       
   318     }
       
   319 
       
   320     return true;
       
   321 }
       
   322 
       
   323 ServiceDatabase *CommandProcessor::initTargetDatabase(const QString &databasePath, bool deleteDbAllowed)
       
   324 {
       
   325     if (!databasePath.isEmpty()) {
       
   326 
       
   327         ServiceDatabase *db = new ServiceDatabase;
       
   328         db->setDatabasePath(databasePath + QDir::separator() + dbName() + QLatin1String(".db"));
       
   329 
       
   330         if (batchMode && deleteDatabase && deleteDbAllowed) {
       
   331             // delete file
       
   332             QFile dbFile(db->databasePath());
       
   333             dbFile.remove();
       
   334         }
       
   335         if (db->open())
       
   336             return db;
       
   337         else
       
   338             delete db;
       
   339     }
       
   340     return NULL;
       
   341 }
       
   342 
       
   343 QString CommandProcessor::getServiceFromXML(const QString &xmlFile)
       
   344 {
       
   345     QFile file(xmlFile);
       
   346     ServiceMetaData data(0);
       
   347     if (file.open(QIODevice::ReadOnly)) {
       
   348         data.setDevice(&file);
       
   349         if (data.extractMetadata()) {
       
   350             return data.parseResults().name;
       
   351         }
       
   352     }
       
   353 
       
   354     return QString();
       
   355 }
       
   356 
       
   357 QStringList CommandProcessor::getServiceDescriptors(const QString &path)
       
   358 {
       
   359     QDir dir(QDir::toNativeSeparators(path));
       
   360     if (!dir.exists()) {
       
   361         return QStringList();
       
   362     }
       
   363     QStringList fileExt;
       
   364     fileExt << "*.xml";
       
   365     QStringList files = dir.entryList(fileExt);
       
   366     QStringList ret;
       
   367     foreach (const QString &f, files) {
       
   368         ret << (QDir::toNativeSeparators(path) + QDir::separator() + f);
       
   369     }
       
   370     return ret;
       
   371 }
       
   372 
       
   373 QStringList CommandProcessor::targetServiceDescriptors(const QString &desPath, const QStringList &args)
       
   374 {
       
   375     if (batchMode) {
       
   376         // arguments are paths or empty!
       
   377         if (args.isEmpty()) {
       
   378             // default path for target
       
   379             QDir::root().mkpath(desPath);
       
   380             return getServiceDescriptors(desPath);
       
   381         }
       
   382         else {
       
   383             // get files from arguments
       
   384             QStringList files;
       
   385             foreach (const QString &folder, args)
       
   386                 files << getServiceDescriptors(folder);
       
   387             return files;
       
   388         }
       
   389     }
       
   390 
       
   391     // individual mode
       
   392     return args;
       
   393 }
       
   394 
       
   395 void CommandProcessor::add(const QStringList &desList, ServiceDatabase *db)
       
   396 {
       
   397     if (desList.isEmpty()) {
       
   398         MESSAGE("ERROR: No descriptor files/path specified, or the path does not contain service descriptors!\n");
       
   399         MESSAGE("Usage:\n\tadd <service-xml-file(s)>[|path-to-service-xmls]\n");
       
   400         showUsage();
       
   401         return;
       
   402     }
       
   403 
       
   404     QString securityToken = QString::number(SEC_TOKEN);
       
   405 
       
   406     foreach (const QString &serviceXml, desList) {
       
   407         QFile f(serviceXml);
       
   408         ServiceMetaData parser(&f);
       
   409         if (!parser.extractMetadata()) {
       
   410             MESSAGE("Parsing error: " << serviceXml << '\n');
       
   411             continue;
       
   412         }
       
   413 
       
   414         const ServiceMetaDataResults results = parser.parseResults();
       
   415         db->unregisterService(results.name, securityToken);
       
   416         if (db->registerService(results, securityToken)) {
       
   417             if (!requireInitialization) {
       
   418                 // remove the previous installation of the service from the database
       
   419                 db->serviceInitialized(results.name, securityToken);
       
   420             }
       
   421             MESSAGE("Service " << results.name << " registered\n");
       
   422         }
       
   423         else
       
   424             MESSAGE("ERROR: Service " << results.name << " registration to " << db->databasePath() << " failed\n");
       
   425     }
       
   426 }
       
   427 
       
   428 void CommandProcessor::remove(const QStringList &desList, ServiceDatabase *db)
       
   429 {
       
   430     if (desList.isEmpty()) {
       
   431         MESSAGE("ERROR: No descriptor files/path specified, or the path does not contain service descriptors!\n");
       
   432         MESSAGE("Usage:\n\tremove <service-xml-file(s)|path-to-service-xmls>\n");
       
   433         return;
       
   434     }
       
   435 
       
   436     QString securityToken = QString::number(SEC_TOKEN);
       
   437 
       
   438     foreach (const QString &serviceXml, desList) {
       
   439         const QString &service = getServiceFromXML(serviceXml);
       
   440         if (service.isEmpty()) {
       
   441             MESSAGE("ERROR: empty service descriptor or wrong parameter given.\n");
       
   442             continue;
       
   443         }
       
   444         if (db->unregisterService(service, securityToken))
       
   445             MESSAGE("Service " << service << " unregistered\n")
       
   446         else
       
   447             MESSAGE("ERROR: Service " << service << " unregistration from " << db->databasePath() << " failed\n");
       
   448     }
       
   449 }
       
   450 
       
   451 Q_IMPORT_PLUGIN(qsqlite)
       
   452 
       
   453 int main(int argc, char *argv[])
       
   454 {
       
   455     QCoreApplication app(argc, argv);
       
   456     QStringList args = QCoreApplication::arguments();
       
   457     CommandProcessor processor;
       
   458 
       
   459     if (!processor.initialize())
       
   460         return 1;
       
   461 
       
   462     if (args.count() == 1 || args.value(1) == "--help" || args.value(1) == "-h") {
       
   463         processor.showUsage();
       
   464         return 0;
       
   465     }
       
   466 
       
   467     QStringList options;
       
   468     for (int i=1; i<args.count(); i++) {
       
   469         if (args[i].startsWith("-"))
       
   470             options += args[i];
       
   471     }
       
   472 
       
   473     processor.execute(options, args.value(options.count() + 1), args.mid(options.count() + 2));
       
   474     return 0;
       
   475 }
       
   476 
       
   477 #include "servicedbgen.moc"