javacommons/javastorage/src/server/storagedbhandler.cpp
changeset 21 2a9601315dfc
child 78 71ad690e91f5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/javastorage/src/server/storagedbhandler.cpp	Mon May 03 12:27:20 2010 +0300
@@ -0,0 +1,439 @@
+/*
+* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  StorageDBHandler
+*
+*/
+
+
+#include <sstream>
+#include <sqlite3.h>
+#include <stdlib.h>
+#include <vector>
+
+#include "javacommonutils.h"
+#include "javastoragenames.h"
+#include "javastoragetables.h"
+#include "logger.h"
+#include "storagedbhandler.h"
+
+using namespace java::storage;
+using namespace java::util;
+using namespace std;
+
+StorageDBHandler::StorageDBHandler()
+{
+    JELOG2(EJavaStorage);
+    iDb = 0;
+    iResultString = L"";
+    mHavingTransaction = false;
+}
+
+StorageDBHandler::~StorageDBHandler()
+{
+    JELOG2(EJavaStorage);
+
+    // close and and remove all open sessions from DB list
+    for (iDbListIter = iDbList.begin();
+            iDbListIter != iDbList.end();
+            iDbListIter++)
+    {
+        if ((*iDbListIter).second != 0)
+        {
+            sqlite3_close((*iDbListIter).second);
+        }
+    }
+    iDbList.clear();
+}
+
+int StorageDBHandler::open(const wstring& aDbName)
+{
+    JELOG2(EJavaStorage);
+    mHavingTransaction = false;
+    char* dbnameAsChar = 0;
+
+    try
+    {
+        dbnameAsChar = JavaCommonUtils::wstringToUtf8(aDbName);
+    }
+    catch (ExceptionBase& eb)
+    {
+        ELOG1(EJavaStorage, "UTF8 conversion error: %s", eb.toString().c_str());
+        return -1;
+    }
+
+    // Create a random session id number for the connection
+    wstring sessionID = JavaCommonUtils::intToWstring(rand());
+    sessionID += JavaCommonUtils::intToWstring(rand());
+    int rc = sqlite3_open(dbnameAsChar, &iDb);
+
+    if (rc)
+    {
+        ELOG1(EJavaStorage, "Cannot open database: %s",
+              sqlite3_errmsg(iDb));
+        sqlite3_close(iDb);
+        delete[] dbnameAsChar;
+        return rc;
+    }
+    else
+    {
+        iCurrentSession.first = sessionID;
+        iCurrentSession.second = iDb;
+        iDbList.push_back(iCurrentSession);
+    }
+
+    if (!isDBInitialized(dbnameAsChar))
+    {
+        LOG(EJavaStorage, EInfo, "Initializing DB.");
+        try
+        {
+            initializeDatabase(dbnameAsChar);
+            LOG(EJavaStorage, EInfo, "DB initialized OK.");
+        }
+        catch (JavaStorageException& jse)
+        {
+            ELOG1(EJavaStorage,
+                  "Init failed: %s",
+                  jse.toString().c_str());
+            rc = EInternalError;
+        }
+    }
+
+    delete[] dbnameAsChar;
+    return rc;
+}
+
+int StorageDBHandler::close()
+{
+    JELOG2(EJavaStorage);
+
+    // If active transaction while closing connection. Rollback is done
+    // to maintain DB consistency.
+    if (mHavingTransaction)
+    {
+        WLOG(EJavaStorage,
+             "Close while active session. Doing rollback");
+        int err = rollback();
+        if (err < 0)
+        {
+            WLOG1(EJavaStorage, "Rollback failed: %d", err);
+        }
+    }
+
+    int rc = sqlite3_close(iDb);
+
+    // remove the session connection object from the connections list
+    for (iDbListIter = iDbList.begin();
+            iDbListIter != iDbList.end();
+            ++iDbListIter)
+    {
+        if (iCurrentSession.first == (*iDbListIter).first)
+        {
+            iDbList.erase(iDbListIter++);
+            break;
+        }
+    }
+    return rc;
+}
+
+int StorageDBHandler::startTransaction()
+{
+    JELOG2(EJavaStorage);
+    int rc = 0;
+    string statement = "BEGIN;";
+    try
+    {
+        executeStandalone(statement);
+        mHavingTransaction = true;
+    }
+    catch (JavaStorageException& jse)
+    {
+        rc = jse.mStatus;
+        mHavingTransaction = false;
+        ELOG1(EJavaStorage,
+              "Transaction start failed: %s",
+              jse.toString().c_str());
+    }
+
+    return rc;
+}
+
+int StorageDBHandler::prepare(const std::wstring& aMessage)
+{
+    JELOG2(EJavaStorage);
+    int rc;
+    const char *tail = 0;
+    int statementBytes = aMessage.length() * 4;
+    char *zErrMsg = 0;
+    char* stmAsChar = 0;
+
+    try
+    {
+        stmAsChar = JavaCommonUtils::wstringToUtf8(aMessage);
+    }
+    catch (ExceptionBase& eb)
+    {
+        ELOG1(EJavaStorage, "UTF8 conversion error: %s", eb.toString().c_str());
+        return -1;
+    }
+
+    rc = sqlite3_prepare_v2(
+             iDb, stmAsChar, statementBytes , &iStatement, &tail);
+
+
+    if (SQLITE_OK != rc)
+    {
+        ELOG1(EJavaStorage, "SQL error on prepare: %d", rc);
+        sqlite3_free(zErrMsg);
+        delete [] stmAsChar;
+        return rc;
+    }
+
+    delete [] stmAsChar;
+
+    return rc;
+}
+
+std::wstring& StorageDBHandler::executeStmt()
+{
+    JELOG2(EJavaStorage);
+    int rc;
+    iResultString.clear();
+    std::wostringstream oss;
+
+    rc = sqlite3_step(iStatement);
+
+    while (SQLITE_ROW == rc)
+    {
+        const char *columnName(0);
+        const unsigned char *column(0);
+        oss << L";#\n;";
+
+        for (int i = 0; i < sqlite3_column_count(iStatement); i++)
+        {
+            column = sqlite3_column_text(iStatement, i);
+
+            if (column)
+            {
+                wstring columnValue = JavaCommonUtils::utf8ToWstring(
+                                          reinterpret_cast<const char*>(column));
+
+                columnName = sqlite3_column_name(iStatement, i);
+                oss << JavaCommonUtils::utf8ToWstring(columnName);
+                oss << L"=" + columnValue + L";\n;";
+            }
+        }
+        rc = sqlite3_step(iStatement);
+    }
+
+    iResultString = oss.str();
+
+    // Return affected rowCount if no other content to be returned.
+    // This is to return e.g. how many rows removed from DB using DELETE
+    // statement.
+    if (L"" == iResultString)
+    {
+        int changes = sqlite3_changes(iDb);
+        iResultString = JavaCommonUtils::intToWstring(changes);
+    }
+
+    // Same statement is not reused.
+    int fc = sqlite3_finalize(iStatement);
+    if (0 != fc)
+    {
+        WLOG1(EJavaStorage, "Finalize failed: %d", fc);
+    }
+
+    return iResultString;
+}
+
+int StorageDBHandler::commit()
+{
+    JELOG2(EJavaStorage);
+    int rc = 0;
+    string statement = "COMMIT;";
+    try
+    {
+        executeStandalone(statement);
+        mHavingTransaction = false;
+    }
+    catch (JavaStorageException& jse)
+    {
+        rc = jse.mStatus;
+        ELOG1(EJavaStorage,
+              "Transaction commit failed: %s",
+              jse.toString().c_str());
+    }
+
+    return rc;
+}
+
+int StorageDBHandler::rollback()
+{
+    JELOG2(EJavaStorage);
+    int rc = 0;
+    string statement = "ROLLBACK;";
+    try
+    {
+        executeStandalone(statement);
+        mHavingTransaction = false;
+    }
+    catch (JavaStorageException& jse)
+    {
+        rc = jse.mStatus;
+        ELOG1(EJavaStorage,
+              "Transaction rollback failed: %s",
+              jse.toString().c_str());
+    }
+
+    return rc;
+}
+
+bool StorageDBHandler::selectConnection(const wstring& aSessionID)
+{
+    JELOG2(EJavaStorage);
+    for (iDbListIter = iDbList.begin();
+            iDbListIter != iDbList.end();
+            iDbListIter++)
+    {
+        iCurrentSession = *iDbListIter;
+        if (iCurrentSession.first == aSessionID)
+        {
+            iDb = iCurrentSession.second;
+            return true;
+        }
+    }
+    return false;
+}
+
+wstring StorageDBHandler::returnSessionID()
+{
+    return iCurrentSession.first;
+}
+
+bool StorageDBHandler::isDBInitialized(const string& aDbName)
+{
+    JELOG2(EJavaStorage);
+    bool result = false;
+
+    string sqlCommand = "SELECT ID FROM ";
+
+    if (JAVA_DATABASE_NAME == aDbName)
+    {
+        sqlCommand.append(APPLICATION_PACKAGE_TABLE);
+    }
+    else if (JAVA_OTA_DATABASE_NAME == aDbName)
+    {
+        sqlCommand.append(OTA_STATUS_TABLE);
+    }
+    else
+    {
+        // Only predefined databases are supported.
+        return result;
+    }
+
+    sqlCommand.append(";");
+
+    try
+    {
+        executeStandalone(sqlCommand);
+        result = true;
+    }
+    catch (JavaStorageException& jse)
+    {
+        WLOG1(EJavaStorage, "DB not init: %s", jse.toString().c_str());
+    }
+    return result;
+}
+
+void StorageDBHandler::initializeDatabase(const string& aDbName)
+throw(JavaStorageException)
+{
+    JELOG2(EJavaStorage);
+
+    if (JAVA_DATABASE_NAME == aDbName)
+    {
+        // Create java database tables.
+        executeStandalone(APPLICATION_PACKAGE);
+        executeStandalone(APPLICATION);
+        executeStandalone(APPLICATION_PACKAGE_ATTRIBUTES);
+        executeStandalone(MIDP_PACKAGE);
+        executeStandalone(MIDP_PERMISSIONS);
+        executeStandalone(MIDP_FUNC_GRP_SETTINGS);
+        executeStandalone(PUSH_REGISTRATIONS);
+        executeStandalone(ALARM_REGISTRATIONS);
+        executeStandalone(RUNTIME_SETTINGS);
+        executeStandalone(PREINSTALL);
+    }
+    else if (JAVA_OTA_DATABASE_NAME == aDbName)
+    {
+        // Create OTA database table.
+        executeStandalone(OTA_STATUS);
+    }
+    else
+    {
+        // Only predefined database init is supported. No error thrown as
+        // db open is still success.
+    }
+}
+
+void StorageDBHandler::executeStandalone(const string& aStatement)
+throw(JavaStorageException)
+{
+    JELOG2(EJavaStorage);
+
+    char *zErrMsg = 0;
+    int rc = -1;
+
+    rc = sqlite3_exec(iDb, aStatement.c_str(), dBCallback, 0, &zErrMsg);
+
+    if (SQLITE_OK != rc)
+    {
+        ELOG2(EJavaStorage, "Db error code: %d msg: %s", rc, zErrMsg);
+        string errString(zErrMsg);
+
+        sqlite3_free(zErrMsg);
+
+        throw JavaStorageException(rc,
+                                   errString.c_str(),
+                                   __FILE__,
+                                   __FUNCTION__,
+                                   __LINE__);
+    }
+}
+
+int StorageDBHandler::dBCallback(void */*NotUsed*/,
+                                 int argc,
+                                 char **argv,
+                                 char **azColName)
+{
+    JELOG2(EJavaStorage);
+    for (int i = 0; i < argc; i++)
+    {
+        ELOG2(EJavaStorage, "    %s = %s",
+              azColName[i], argv[i] ? argv[i] : "NULL");
+    }
+    return 0;
+}
+
+const char* StorageDBHandler::getErrorMessage()
+{
+    JELOG2(EJavaStorage);
+    return sqlite3_errmsg(iDb);
+}
+
+int StorageDBHandler::getErrorCode()
+{
+    JELOG2(EJavaStorage);
+    return sqlite3_errcode(iDb);
+}