summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDenis Dzyubenko <denis.dzyubenko@nokia.com>2011-10-25 11:31:53 +0200
committerDenis Dzyubenko <denis.dzyubenko@nokia.com>2011-10-25 11:31:53 +0200
commit79ab0a667e9d9d11cc1de0f3ed21a37f5c2909ee (patch)
treedefc8568b03b974ec7b306f9e32dab38d97951e9 /tools
Long live QtJsonDb!
Diffstat (limited to 'tools')
-rw-r--r--tools/adb-dump/adb-dump.pro19
-rw-r--r--tools/adb-dump/main.cpp82
-rw-r--r--tools/aodbread/aodbread.pro19
-rw-r--r--tools/aodbread/main.cpp303
-rw-r--r--tools/jsondb-client/client.cpp501
-rw-r--r--tools/jsondb-client/client.h115
-rw-r--r--tools/jsondb-client/jsondb-client.pro16
-rw-r--r--tools/jsondb-client/main.cpp118
-rw-r--r--tools/tools.pro3
9 files changed, 1176 insertions, 0 deletions
diff --git a/tools/adb-dump/adb-dump.pro b/tools/adb-dump/adb-dump.pro
new file mode 100644
index 00000000..454f3a85
--- /dev/null
+++ b/tools/adb-dump/adb-dump.pro
@@ -0,0 +1,19 @@
+include($$PWD/../../src/3rdparty/btree/btree.pri)
+
+TARGET = adb-dump
+DESTDIR = $$QT.jsondb.bins
+
+target.path = $$[QT_INSTALL_BINS]
+INSTALLS += target
+
+QT = core
+
+mac:CONFIG -= app_bundle
+
+!mac:LIBS += -lcrypto
+
+INCLUDEPATH += ../../src/daemon
+
+HEADERS += ../../src/daemon/aodb.h
+
+SOURCES += main.cpp ../../src/daemon/aodb.cpp
diff --git a/tools/adb-dump/main.cpp b/tools/adb-dump/main.cpp
new file mode 100644
index 00000000..7978c829
--- /dev/null
+++ b/tools/adb-dump/main.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation
+ */
+
+#include "aodb.h"
+#include <iostream>
+#include <QCoreApplication>
+#include <QStringList>
+#include <QDebug>
+
+QString progname;
+bool gCompact = false;
+
+/***************************************************************************/
+
+using namespace std;
+
+static void usage()
+{
+ cout << "Usage: " << qPrintable(progname) << " [OPTIONS] [<.db filename>]" << endl
+ << endl << "OPTIONS:" << endl
+ << "-compact\tcompacts the db file before dumping." << endl << endl;
+ exit(0);
+}
+
+
+int main(int argc, char * argv[])
+{
+ QCoreApplication::setOrganizationName("Nokia");
+ QCoreApplication::setOrganizationDomain("nrcc.noklab.com");
+ QCoreApplication::setApplicationName("adb-dump");
+ QCoreApplication::setApplicationVersion("1.0");
+
+ QCoreApplication app(argc, argv);
+ QStringList args = QCoreApplication::arguments();
+
+ progname = args.takeFirst();
+ while (args.size()) {
+ QString arg = args.at(0);
+ if (!arg.startsWith("-"))
+ break;
+ args.removeFirst();
+ if ( arg == "-help")
+ usage();
+ else if ( arg == "-compact")
+ gCompact = true;
+ /*else if (arg == "-load") {
+ if (args.isEmpty()) {
+ cout << "Invalid argument " << qPrintable(arg) << endl;
+ usage();
+ return 0;
+ }
+ loadFile = args.at(0);
+ args.removeFirst();
+ }*/ else {
+ cout << "Unknown argument " << qPrintable(arg) << endl;
+ usage();
+ return 0;
+ }
+ }
+
+ AoDb aoDB;
+ while (args.size()) {
+ QString adbFileName = args.takeFirst();
+ qDebug();
+ if (gCompact) {
+ qDebug() << "Compacting...";
+ aoDB.open(adbFileName, AoDb::NoSync);
+ aoDB.compact();
+ }
+ else
+ aoDB.open(adbFileName, AoDb::ReadOnly|AoDb::NoSync);
+
+ qDebug () << "Dumping file: " << adbFileName;
+ qDebug () << "=============================================================";
+ aoDB.dump();
+ qDebug (); qDebug ();
+ aoDB.close();
+ }
+
+ return 0;
+}
diff --git a/tools/aodbread/aodbread.pro b/tools/aodbread/aodbread.pro
new file mode 100644
index 00000000..f86af6f1
--- /dev/null
+++ b/tools/aodbread/aodbread.pro
@@ -0,0 +1,19 @@
+TARGET = aodbread
+
+QT = network declarative testlib
+CONFIG -= app_bundle
+CONFIG += debug
+
+include($$PWD/../../src/common/common.pri)
+
+INCLUDEPATH += $$PWD/../../src/daemon
+LIBS += -L$$QT.jsondb.libs
+!mac:LIBS += -lssl -lcrypto
+
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+include($$PWD/../../src/daemon/daemon.pri)
+
+SOURCES += \
+ main.cpp \
+
diff --git a/tools/aodbread/main.cpp b/tools/aodbread/main.cpp
new file mode 100644
index 00000000..d45eb757
--- /dev/null
+++ b/tools/aodbread/main.cpp
@@ -0,0 +1,303 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+
+#include "aodb.h"
+#include "btree.h"
+
+#include "qson/qson.h"
+#include "qson/qsonparser.h"
+
+#include "json.h"
+
+Q_USE_JSONDB_NAMESPACE
+
+QString printable(const QByteArray &ba)
+{
+ QByteArray array = ba;
+
+ if (ba.startsWith("QSN")) {
+ QVariant obj = qsonToVariant(QsonParser::fromRawData(ba));
+ JsonWriter writer;
+// writer.setAutoFormatting(true);
+ return QString("QSN:") +writer.toString(obj);
+ }
+
+ // check if it is a number
+ bool isNumber = true;
+ for (int i = 0; i < array.size(); ++i) {
+ if (array.at(i) < 0 || array.at(i) > 9) {
+ isNumber = false;
+ break;
+ }
+ }
+ if (isNumber) {
+ for (int i = 0; i < array.size(); ++i) {
+ array[i] = array.at(i)+'0';
+ }
+ return QString("N:") +QString::fromLatin1(array);
+ }
+
+ // check if utf-16 latin string
+ bool utf16 = true;
+ for (int i = 0; i < array.size(); ++i) {
+ if (i % 2 == 0) {
+ if (!isprint(array.at(i))) {
+ utf16 = false;
+ break;
+ }
+ } else {
+ if (array.at(i) != 0) {
+ utf16 = false;
+ break;
+ }
+ }
+ }
+ if (utf16) {
+ return QString("U:") + QString::fromUtf16((const ushort *)array.constData(), array.size()/2);
+ }
+
+ for (int i = 0; i < array.size(); ++i) {
+ if (array.at(i) == 0)
+ array[i] = '_';
+ }
+
+ bool isprintable = true;
+ for (int i = 0; i < array.size(); ++i) {
+ if (!isprint(array.at(i))) {
+ isprintable = false;
+ break;
+ }
+ }
+ if (isprintable) {
+ return QString("S:") + QString::fromLatin1(array);
+ }
+
+ if (ba.size() == 5 && ba.at(4) == 'S') {
+ // state change
+ quint32 state = qFromBigEndian<quint32>((const uchar *)ba.mid(0, 4).constData());
+ return QString("State:") + QString::number(state);
+ }
+ array = ba.toHex();
+ return QString("x:") + QString::fromLatin1(array);
+}
+
+void makePrintable(const QByteArray &key, QString &keyString, const QByteArray &value, QString &valueString)
+{
+ if (key.size() == 5 && key.at(4) == 'S') {
+ // state change
+ quint32 state = qFromBigEndian<quint32>((const uchar *)key.mid(0, 4).constData());
+ keyString = QString("State:") + QString::number(state);
+
+ QStringList changes;
+ const uchar *data = (const uchar *)value.constData();
+ for (int i = 0; i < value.size() / 16; ++i) {
+ quint32 startKey = qFromBigEndian<quint32>(&data[16 * i]);
+ quint32 startTypeNumber = qFromBigEndian<quint32>(&data[16 * i + 4]);
+ quint32 endKey = qFromBigEndian<quint32>(&data[16 * i + 8]);
+ quint32 endTypeNumber = qFromBigEndian<quint32>(&data[16 * i + 12]);
+ changes << QString("objectTypeKey %2->%4, objectKey %1->%3").arg(startKey).arg(startTypeNumber).arg(endKey).arg(endTypeNumber);
+ }
+ valueString = changes.join(",");
+ return;
+ }
+
+ keyString = printable(key);
+ valueString = printable(value);
+}
+
+bool gStat = false;
+bool gDump = false;
+bool gWantCompact = false;
+bool gShowAll = false;
+bool gShowAllReversed = false;
+quint32 gShowState = 0;
+qint64 gDumpPage = 0;
+
+void usage()
+{
+ qDebug() << QCoreApplication::arguments().at(0)
+ << "[--dump-page num] [--stat] [--dump] [--compact] [--all|--all-reversed] [--state num] database_file";
+}
+
+int main(int argc, char **argv)
+{
+ QCoreApplication app(argc, argv);
+
+ QStringList args = app.arguments();
+ args.pop_front();
+
+ if (args.isEmpty()) {
+ usage();
+ return 0;
+ }
+
+ for (; args.size() > 1; ) {
+ QString arg = args.takeFirst();
+ if (arg == QLatin1String("--stat")) {
+ gStat = true;
+ } else if (arg == QLatin1String("--dump")) {
+ gDump = true;
+ } else if (arg == QLatin1String("--compact")) {
+ gWantCompact = true;
+ } else if (arg == QLatin1String("--all")) {
+ gShowAll = true;
+ } else if (arg == QLatin1String("--all-reversed")) {
+ gShowAllReversed = true;
+ } else if (arg == QLatin1String("--state")) {
+ bool ok = false;
+ gShowState = args.takeFirst().toInt(&ok);
+ if (!ok) {
+ usage();
+ return 0;
+ }
+ } else if (arg == QLatin1String("--dump-page")) {
+ bool ok = false;
+ gDumpPage = args.takeFirst().toInt(&ok);
+ if (!ok) {
+ usage();
+ return 0;
+ }
+ } else {
+ usage();
+ return 0;
+ }
+ }
+
+ if (args.isEmpty())
+ return 0;
+
+ QString filename = args.at(0);
+
+ if (gDumpPage > 0) {
+ return btree_dump_page(filename.toLocal8Bit().constData(), gDumpPage);
+ } else if (gDumpPage < 0) {
+ uint32_t page = 1;
+ while (btree_dump_page(filename.toLocal8Bit().constData(), page))
+ ++page;
+ return 1;
+ }
+
+ AoDb db;
+ if (!db.open(filename, AoDb::ReadOnly)) {
+ qDebug() << "cannot open" << filename;
+ usage();
+ return 0;
+ }
+
+ if (gStat) {
+ const struct btree_stat *bs = db.stat();
+ qDebug() << "stat:";
+ qDebug() << "\thits:" << bs->hits;
+ qDebug() << "\treads:" << bs->reads;
+ qDebug() << "\tmax_cache:" << bs->max_cache;
+ qDebug() << "\tbranch_pages:" << bs->branch_pages;
+ qDebug() << "\tleaf_pages:" << bs->leaf_pages;
+ qDebug() << "\toverflow_pages:" << bs->overflow_pages;
+ qDebug() << "\trevisions:" << bs->revisions;
+ qDebug() << "\tdepth:" << bs->depth;
+ qDebug() << "\tentries:" << bs->entries;
+ qDebug() << "\tpsize:" << bs->psize;
+ qDebug() << "\tcreated_at:" << bs->created_at << "(" << QDateTime::fromTime_t(bs->created_at) << ")";
+ qDebug() << "\ttag:" << bs->tag;
+ qDebug() << "";
+ }
+ if (gDump) {
+ db.dump();
+ }
+
+ if (gShowState != 0) {
+#if 0
+ AoDb statedb;
+ QFileInfo fi(filename);
+ if (!statedb.open(QString("%1/%2-States.db").arg(fi.dir().path()).arg(fi.baseName()), AoDb::ReadOnly)) {
+ qDebug() << "cannot open" << filename;
+ usage();
+ return 0;
+ }
+ ObjectCursor cursor(&statedb, &db);
+ bool ok = cursor.first(gShowState);
+ if (!ok) {
+ qDebug() << "Could not seek to" << gShowState;
+ return 0;
+ }
+ QByteArray key, value;
+ for (int i = 0; ok && cursor.current(key, value); ok = cursor.next(), ++i) {
+ QString keyString, valueString;
+ makePrintable(key, keyString, value, valueString);
+ qDebug() << i << ":" << keyString << ":" << valueString;
+ }
+#endif
+ }
+
+ if (gShowAllReversed) {
+ AoDbCursor cursor(&db);
+ QByteArray key, value;
+ int i = 0;
+ for (bool ok = cursor.last(); ok && cursor.current(key, value); ok = cursor.prev(), ++i) {
+ QString keyString, valueString;
+ makePrintable(key, keyString, value, valueString);
+ qDebug() << i << ":" << keyString << ":" << valueString;
+ }
+ } else if (gShowAll) {
+ AoDbCursor cursor(&db);
+ QByteArray key, value;
+ int i = 0;
+ for (bool ok = cursor.first(); ok && cursor.current(key, value); ok = cursor.next(), ++i) {
+ QString keyString, valueString;
+ makePrintable(key, keyString, value, valueString);
+ qDebug() << i << ":" << keyString << ":" << valueString;
+ }
+ }
+
+ if (gWantCompact) {
+ db.close();
+ db.open(filename);
+ if (db.compact()) {
+ qDebug() << "compacted.";
+ } else {
+ qDebug() << "failed to compact" << filename;
+ }
+ db.close();
+ }
+ return 1;
+}
diff --git a/tools/jsondb-client/client.cpp b/tools/jsondb-client/client.cpp
new file mode 100644
index 00000000..1e674bcb
--- /dev/null
+++ b/tools/jsondb-client/client.cpp
@@ -0,0 +1,501 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QSocketNotifier>
+#include <QCoreApplication>
+#include <QStringBuilder>
+#include <QMetaObject>
+#include <QThread>
+#include <QVariant>
+#include <QDir>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+#include "json.h"
+
+#include "client.h"
+
+Q_USE_JSONDB_NAMESPACE
+
+extern bool gDebug;
+
+const char* InputThread::commands[] = { "changesSince",
+ "create {\"",
+ "find",
+ "help",
+ "notify create [?",
+ "notify remove [?",
+ "notify update [?",
+ "query [?",
+ "quit",
+ "remove",
+ "update",
+ 0 };
+
+InputThread *InputThread::threadInstance = 0;
+
+InputThread *InputThread::instance()
+{
+ if (!threadInstance)
+ threadInstance = new InputThread;
+ return threadInstance;
+}
+
+InputThread::~InputThread()
+{
+ if (hist && !historyFile.isEmpty())
+ history(hist, 0, H_SAVE, historyFile.toLocal8Bit().constData());
+ if (hist) {
+ history_end(hist);
+ hist = 0;
+ }
+}
+
+char const* InputThread::prompt(EditLine *e)
+{
+ Q_UNUSED(e);
+ char const* string = "jclient> ";
+ return string;
+}
+
+QString InputThread::longestCommonPrefix(const QStringList &list)
+{
+ if (list.size() > 1) {
+ QChar temp;
+ int pos = 0;
+ for (bool roundComplete = true; roundComplete; pos++) {
+ for (int i = 0; i < list.size(); i++) {
+ QString entry = list[i];
+ if (entry.length() <= pos) {
+ roundComplete = false;
+ break;
+ } else if (i == 0)
+ temp = list[i][pos];
+ else {
+ if (temp != list[i][pos]) {
+ roundComplete = false;
+ break;
+ }
+ }
+ }
+ }
+ return list[0].left(pos-1);
+ } else if (list.size() == 1)
+ return list[0];
+ else
+ return QString();
+}
+
+unsigned char InputThread::console_tabkey(EditLine * el, int ch)
+{
+ Q_UNUSED(ch);
+ QStringList matches;
+ const LineInfo *lineInfo = el_line(el);
+ for (int i = 0; commands[i] != 0; i++) {
+ int compare = qstrncmp(commands[i], lineInfo->buffer, lineInfo->lastchar-lineInfo->buffer);
+ if (compare == 0) {
+ matches << QString::fromLocal8Bit(commands[i]);
+ }
+ }
+
+ int m = matches.size();
+ if (m == 1) {
+ QString missing = matches[0].remove(0,lineInfo->lastchar-lineInfo->buffer);
+ el_insertstr(el, qPrintable(missing));
+ return CC_REFRESH;
+ } else if (m > 1) {
+ instance()->async_print("\n" % matches.join("\n"));
+ QString missing = longestCommonPrefix(matches).remove(0,lineInfo->lastchar-lineInfo->buffer);
+ el_insertstr(el, qPrintable(missing));
+ return CC_REFRESH;
+ }
+ return CC_ARGHACK;
+}
+
+void InputThread::run()
+{
+ int count;
+ const char *line;
+ HistEvent ev;
+
+ el = el_init("jsondb-client", stdin, stdout, stderr);
+ el_set(el, EL_PROMPT, &prompt);
+ el_set(el, EL_EDITOR, "emacs");
+ hist = history_init();
+ el_set(el, EL_ADDFN, "tab-key", "TAB KEY PRESS", console_tabkey);
+ if (hist == 0) {
+ qDebug() << "initializing the history failed.";
+ exit(-1);
+ }
+ history(hist, &ev, H_SETSIZE, 800);
+ historyFile = QDir::homePath() + QDir::separator() + QLatin1String(".jsondb/history");
+ history(hist, &ev, H_LOAD, historyFile.toLocal8Bit().constData());
+ el_set(el, EL_HIST, history, hist);
+ el_set(el, EL_BIND, "\t", "tab-key", NULL);
+
+ while (true) {
+ line = el_gets(el, &count);
+
+ if (count > 0) {
+ QString cmd = QString(line).trimmed();
+ if (cmd == "quit")
+ break;
+ else if (!cmd.isEmpty()) {
+ emit (commandReceived(cmd));
+ history(hist, &ev, H_ENTER, line);
+ }
+ }
+ }
+
+ history(hist, &ev, H_SAVE, historyFile.toLocal8Bit().constData());
+ history_end(hist);
+ hist = 0;
+ el_end(el);
+
+ exit(0);
+}
+
+void InputThread::print(const QString &message)
+{
+ if (threadInstance) {
+ instance()->async_print(message);
+ } else {
+ std::cout << qPrintable(message) << std::endl;
+ }
+}
+
+void InputThread::async_print(const QString &message)
+{
+ QString clear(strlen(prompt(0)), QChar('\b'));
+ std::cout << qPrintable(clear) << qPrintable(message) << std::endl;
+ el_set(el, EL_REFRESH);
+}
+
+Client::Client( QObject *parent )
+ : QObject(parent), mNotifier(NULL), mInputThread(NULL)
+{
+}
+
+Client::~Client()
+{
+ if (mInputThread) {
+ mInputThread->terminate();
+ mInputThread->wait(1000);
+ delete mInputThread;
+ mInputThread = 0;
+ }
+}
+
+bool Client::connectToServer()
+{
+ QString socketName = ::getenv("JSONDB_SOCKET");
+ if (socketName.isEmpty()) {
+ mConnection = new QtAddOn::JsonDb::JsonDbClient(this);
+ } else {
+ mConnection = new QtAddOn::JsonDb::JsonDbClient(socketName, this);
+ }
+
+ connect(mConnection, SIGNAL(disconnected()), this, SLOT(disconnected()));
+ connect(mConnection, SIGNAL(response(int,QVariant)),
+ this, SLOT(response(int,QVariant)));
+ connect(mConnection, SIGNAL(error(int,int,QString)),
+ this, SLOT(error(int,int,QString)));
+ connect(mConnection, SIGNAL(notified(QString,QVariant,QString)),
+ this, SLOT(notified(QString,QVariant,QString)));
+
+ if (!mConnection->isConnected()) {
+ qCritical() << "Unable to connect to server";
+ return false;
+ }
+ return true;
+}
+
+void Client::interactiveMode()
+{
+ mInputThread = InputThread::instance();
+ connect(mInputThread, SIGNAL(commandReceived(QString)), this, SLOT(processCommand(QString)));
+ connect(mInputThread, SIGNAL(finished()), QCoreApplication::instance(), SLOT(quit()));
+ mInputThread->start();
+}
+
+void Client::disconnected()
+{
+ qCritical() << "Lost connection to the server";
+ QCoreApplication::exit(0);
+}
+
+void Client::notified(const QString &notify_uuid, const QVariant &object, const QString &action)
+{
+ JsonWriter writer;
+ writer.setAutoFormatting(true);
+ QString buf = writer.toString(object);
+
+ QString message = "Received notification: type " % action
+ % " for " % notify_uuid % " object:\n" % buf;
+ InputThread::print(message);
+
+ if (!mInputThread)
+ QCoreApplication::exit(0); // Non-interactive mode just stops
+}
+
+void Client::response(int id, const QVariant &msg)
+{
+ Q_UNUSED(id);
+ JsonWriter writer;
+ writer.setAutoFormatting(true);
+ QString buf = writer.toString(msg);
+
+ QString message = "Received message: " % buf;
+ InputThread::print(message);
+
+ mRequests.remove(id);
+ if (mRequests.isEmpty())
+ emit requestsProcessed();
+
+ if (!mInputThread)
+ QCoreApplication::exit(0); // Non-interactive mode just stops
+}
+
+void Client::error(int, int code, const QString &msg)
+{
+ QString message = "Received error " % QString().setNum(code) % ":" % msg;
+ InputThread::print(message);
+
+ if (!mInputThread)
+ QCoreApplication::exit(0); // Non-interactive mode just stops
+}
+
+void Client::usage()
+{
+ std::stringstream out;
+ out << "Valid commands:" << std::endl
+ << std::endl
+ << "Direct database commands - these take an explict object" << std::endl
+ << " create OBJECT" << std::endl
+ << " update OBJECT" << std::endl
+ << " remove OBJECT" << std::endl
+ << " remove QUERY" << std::endl
+ << " find QUERY" << std::endl
+ << " changesSince STATENUMBER [type1 type2 ...]" << std::endl
+ << std::endl
+ << "Convenience functions" << std::endl
+ << " query STRING [offset [limit]]" << std::endl
+ << " find {\"query\": STRING}" << std::endl
+ << " notify ACTIONS QUERY" << std::endl
+ << " create { \"_type\": \"notification\"," << std::endl
+ << " \"query\": QUERY," << std::endl
+ << " \"actions\": ACTIONS }" << std::endl
+ << " help" << std::endl
+ << " quit" << std::endl
+ << std::endl
+ << "ACTIONS: comma separated list. Valid values: create, update, remove" << std::endl
+ << "OBJECT: Valid JSON object" << std::endl
+ << "QUERY: Valid JSONQuery command" << std::endl
+ << std::endl
+ << "Sample commands: " << std::endl
+ << " create {\"_type\": \"duck\", \"name\": \"Fred\"}" << std::endl
+ << " query [?_type=\"duck\"]" << std::endl
+ << " notify create,remove [?_type=\"duck\"]" << std::endl;
+
+ QString usageInfo = QString::fromStdString(out.str());
+ InputThread::print(usageInfo);
+}
+
+bool Client::processCommand(const QString &command)
+{
+ QString cmd = command.trimmed();
+ QString rest;
+
+ int space = command.indexOf(' ');
+ if (space > 0) {
+ cmd = command.left(space);
+ rest = command.mid(space+1).trimmed();
+ }
+
+ gDebug = true;
+
+ if (cmd == "quit") {
+ exit(0);
+ } else if (cmd == "help") {
+ usage();
+ } else if (cmd == "query") {
+ int offset = 0, limit = -1;
+ int idx = rest.lastIndexOf(']');
+ if (idx != -1) {
+ QStringList list = rest.mid(idx+1).split(' ');
+ int i = 0;
+ for (; i < list.size(); ++i) {
+ if (!list.at(i).trimmed().isEmpty()) {
+ offset = list.at(i).toInt();
+ break;
+ }
+ }
+ for (++i; i < list.size(); ++i) {
+ if (!list.at(i).trimmed().isEmpty()) {
+ limit = list.at(i).toInt();
+ break;
+ }
+ }
+ rest.truncate(idx+1);
+ }
+ if (gDebug)
+ qDebug() << "Sending query:" << QVariant(rest);
+ mRequests << mConnection->query(rest, offset, limit);
+ } else if (cmd == "notify") {
+ int s = rest.indexOf(' ');
+ if (s <= 0)
+ return false;
+ QStringList alist = rest.left(s).split(QRegExp(","), QString::SkipEmptyParts);
+ QtAddOn::JsonDb::JsonDbClient::NotifyTypes actions;
+ foreach (const QString &s, alist) {
+ JsonDbClient::NotifyType type = JsonDbClient::NotifyType(0);
+ if (s == QLatin1String("create"))
+ type = JsonDbClient::NotifyCreate;
+ if (s == QLatin1String("remove"))
+ type = JsonDbClient::NotifyRemove;
+ if (s == QLatin1String("update"))
+ type = JsonDbClient::NotifyUpdate;
+ if (type == JsonDbClient::NotifyType(0)) {
+ InputThread::print("uknown notification type" % s);
+ return false;
+ }
+ actions |= type;
+ }
+ QString query = rest.mid(s+1).trimmed();
+ if (gDebug)
+ qDebug() << "Creating notification:" << alist << ":" << query;
+ mRequests << mConnection->notify(actions, query);
+ } else if (cmd == "remove") {
+ rest = rest.trimmed();
+ bool isquery = false;
+ int i = 0;
+ const int len = rest.length();
+ if (i < len) {
+ if (rest.at(i++) == QLatin1Char('[')) {
+ while (i < len && rest.at(i) == QLatin1Char(' ')) ++i;
+ if (i < len && rest.at(i) == QLatin1Char('?'))
+ isquery = true;
+ }
+ }
+ if (isquery) {
+ // if not json format, then it is a query
+ if (gDebug)
+ qDebug() << "Sending remove for:" << rest;
+ mRequests << mConnection->remove(rest);
+ } else {
+ JsonReader parser;
+ bool ok = parser.parse(rest);
+ if (!ok) {
+ InputThread::print("Unable to parse: " % rest);
+ usage();
+ return false;
+ }
+ QVariant arg = parser.result();
+ if (gDebug)
+ qDebug() << "Sending remove:" << arg;
+ mRequests << mConnection->remove(QVariant(arg));
+ }
+ } else if (cmd == "create" || cmd == "update" || cmd == "find" ) {
+ JsonReader parser;
+ bool ok = parser.parse(rest);
+ if (!ok) {
+ InputThread::print("Unable to parse: " % rest);
+ usage();
+ return false;
+ }
+ QVariant arg = parser.result();
+ if (gDebug)
+ qDebug() << "Sending" << cmd << ":" << arg;
+ int id = 0;
+ QMetaObject::invokeMethod(mConnection, cmd.toLatin1(), Q_RETURN_ARG(int, id), Q_ARG(QVariant, arg));
+ mRequests << id;
+ } else if (cmd == "changesSince") {
+ int stateNumber = 0;
+ QStringList types;
+ QStringList args = rest.split(" ");
+
+ if (args.isEmpty()) {
+ InputThread::print("Must specify the state number");
+ usage();
+ return false;
+ }
+
+ stateNumber = args.takeFirst().trimmed().toInt();
+
+ if (!args.isEmpty())
+ types = args;
+
+ if (gDebug)
+ qDebug() << "Sending changesSince: " << stateNumber << "types: " << types;
+
+ mRequests << mConnection->changesSince(stateNumber, types);
+ } else if (!cmd.isEmpty()) {
+ InputThread::print("Unrecognized command: " % cmd);
+ usage();
+ return false;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool Client::loadJsonFile(const QString &fileName)
+{
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly)) {
+ if (gDebug)
+ qDebug() << "Couldn't load file" << fileName;
+ return false;
+ }
+ JsonReader parser;
+ bool ok = parser.parse(file.readAll());
+ file.close();
+ if (!ok) {
+ std::cout << "Unable to parse the content of the file" << qPrintable(fileName) << ":"
+ << qPrintable(parser.errorString()) << std::endl;
+ return false;
+ }
+ QVariant arg = parser.result();
+ mRequests << mConnection->create(arg);
+ return true;
+}
diff --git a/tools/jsondb-client/client.h b/tools/jsondb-client/client.h
new file mode 100644
index 00000000..1c2f839d
--- /dev/null
+++ b/tools/jsondb-client/client.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#include <QObject>
+#include <QThread>
+#include <QStringList>
+#include <QLocalSocket>
+#include <QSocketNotifier>
+#include <QFile>
+
+#include <histedit.h>
+
+#include "jsondb-client.h"
+
+
+
+class InputThread : public QThread {
+ Q_OBJECT
+public:
+ static InputThread *instance();
+ ~InputThread();
+ void run();
+ void async_print(const QString &);
+ static void print(const QString &);
+ static char const* prompt(EditLine *e);
+ static unsigned char console_tabkey(EditLine * el, int ch);
+signals:
+ void commandReceived(QString);
+private:
+ EditLine *el;
+ History *hist;
+ QString historyFile;
+ InputThread(QObject *parent = 0) : QThread(parent), el(0), hist(0) {}
+ static QString longestCommonPrefix(const QStringList &list);
+ static InputThread *threadInstance;
+ static const char *commands[];
+};
+
+class Client : public QObject
+{
+ Q_OBJECT
+public:
+ Client(QObject *parent = 0);
+ ~Client();
+
+ bool connectToServer();
+ void interactiveMode();
+
+public slots:
+ bool processCommand(const QString &); // true if we're waiting for a response
+ bool loadJsonFile(const QString &fileName);
+
+protected slots:
+ void disconnected();
+
+ void response(int, const QVariant &map);
+ void error(int id, int code, const QString &message);
+ void notified(const QString &notify_uuid, const QVariant &object, const QString &action);
+
+signals:
+ void requestsProcessed();
+
+private:
+ void usage();
+
+ QSocketNotifier *mNotifier;
+ QFile *mInput;
+ QtAddOn::JsonDb::JsonDbClient *mConnection;
+ QSet<int> mRequests;
+ InputThread *mInputThread;
+};
+
+
+#endif // CLIENT_H
diff --git a/tools/jsondb-client/jsondb-client.pro b/tools/jsondb-client/jsondb-client.pro
new file mode 100644
index 00000000..a1b1ef9a
--- /dev/null
+++ b/tools/jsondb-client/jsondb-client.pro
@@ -0,0 +1,16 @@
+TARGET = jsondb-client
+DESTDIR = $$QT.jsondb.bins
+
+target.path = $$[QT_INSTALL_BINS]
+INSTALLS += target
+
+QT = core network declarative jsondb
+
+LIBS += -ledit -lcurses
+
+include(../../src/3rdparty/qjson/qjson.pri)
+
+mac:CONFIG -= app_bundle
+
+HEADERS += client.h
+SOURCES += main.cpp client.cpp
diff --git a/tools/jsondb-client/main.cpp b/tools/jsondb-client/main.cpp
new file mode 100644
index 00000000..a6cc6482
--- /dev/null
+++ b/tools/jsondb-client/main.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2010-2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtAddOn.JsonDb module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include <iostream>
+#include "client.h"
+
+QString progname;
+bool gDebug;
+
+/***************************************************************************/
+
+using namespace std;
+
+static void usage()
+{
+ cout << "Usage: " << qPrintable(progname) << " [OPTIONS] [command]" << endl
+ << endl
+ << " -debug" << endl
+ << " -load file.json Load objects from a json file" << endl
+ << endl
+ << " where command is valid JsonDb command object" << endl;
+ exit(0);
+}
+
+
+int main(int argc, char * argv[])
+{
+ QCoreApplication::setOrganizationName("Nokia");
+ QCoreApplication::setOrganizationDomain("nrcc.noklab.com");
+ QCoreApplication::setApplicationName("jclient");
+ QCoreApplication::setApplicationVersion("1.0");
+
+ QCoreApplication app(argc, argv);
+ QStringList args = QCoreApplication::arguments();
+ QString loadFile;
+
+ progname = args.takeFirst();
+ while (args.size()) {
+ QString arg = args.at(0);
+ if (!arg.startsWith("-"))
+ break;
+ args.removeFirst();
+ if ( arg == "-help")
+ usage();
+ else if ( arg == "-debug")
+ gDebug = true;
+ else if (arg == "-load") {
+ if (args.isEmpty()) {
+ cout << "Invalid argument " << qPrintable(arg) << endl;
+ usage();
+ return 0;
+ }
+ loadFile = args.at(0);
+ args.removeFirst();
+ } else {
+ cout << "Unknown argument " << qPrintable(arg) << endl;
+ usage();
+ return 0;
+ }
+ }
+
+ Client client;
+ if (!client.connectToServer())
+ return 0;
+
+ bool interactive = !args.size();
+ if (!interactive)
+ QObject::connect(&client, SIGNAL(requestsProcessed()), &app, SLOT(quit()));
+
+ if (!loadFile.isEmpty()) {
+ client.loadJsonFile(loadFile);
+ } else if (!args.size()) {
+ client.interactiveMode();
+ } else {
+ if (!client.processCommand(args.join(" ")))
+ return 0;
+ }
+ return app.exec();
+}
diff --git a/tools/tools.pro b/tools/tools.pro
new file mode 100644
index 00000000..d6211f9a
--- /dev/null
+++ b/tools/tools.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS += jsondb-client adb-dump
+