javacommons/javastorage/src.s60/client/javadataaccessimpl.cpp
branchRCL_3
changeset 19 04becd199f91
child 78 71ad690e91f5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/javastorage/src.s60/client/javadataaccessimpl.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,557 @@
+/*
+* 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:  JavaDataAccessImpl
+*
+*/
+
+#include <memory>
+
+#include "commsmessage.h"
+#include "javacommonutils.h"
+#include "javadataaccessimpl.h"
+#include "javastorageexception.h"
+#include "javastoragemessage.h"
+#include "javastoragenames.h"
+#include "javastoragetables.h"
+#include "javasymbianoslayer.h"
+#include "javauids.h"
+#include "logger.h"
+
+using namespace java::comms;
+using namespace java::storage;
+using namespace java::util;
+using namespace std;
+
+const int OK = 0;
+_LIT8(KJavaDbTimeoutOption, "QSQLITE_BUSY_TIMEOUT==10000;");
+
+JavaDataAccessImpl::JavaDataAccessImpl()
+        : mConnOpen(false), mHavingTransaction(false)
+{
+}
+
+OS_EXPORT JavaDataAccessImpl::~JavaDataAccessImpl()
+{
+    JELOG2(EJavaStorage);
+
+    if (mHavingTransaction)
+    {
+        WLOG(EJavaStorage,
+             "Active transaction while deleting. Rollback.");
+
+        _LIT(KRollbackStatement, "ROLLBACK;");
+        TInt err = mDatabase.Exec(KRollbackStatement);
+    }
+
+    if (mConnOpen)
+    {
+        mDatabase.Close();
+    }
+}
+
+OS_EXPORT void JavaDataAccessImpl::open(
+    const string& /*aHeaders*/,
+    const string& aStorageName,
+    CommsMessage& aReceivedMessage) throw(JavaStorageException)
+{
+    JELOG2(EJavaStorage);
+
+    int status = OK;
+
+    if (!mConnOpen)
+    {
+        try
+        {
+            openDatabase(aStorageName);
+        }
+        catch (JavaStorageException& aJse)
+        {
+            status = aJse.mStatus;
+        }
+    }
+    else
+    {
+        WLOG(EJavaStorage, "Connection already open");
+    }
+
+    // SessionID is not needed in this platform context.
+    mSessionId = "N/A";
+
+    aReceivedMessage<<status;
+    aReceivedMessage<<mSessionId;
+}
+
+bool JavaDataAccessImpl::isDBInitialized(const string& aStorageName)
+{
+    JELOG2(EJavaStorage);
+    bool result = false;
+    string sqlStatement = "SELECT ";
+
+    if (JAVA_DATABASE_NAME == aStorageName)
+    {
+        sqlStatement.append("NAME FROM ");
+        sqlStatement.append(PREINSTALL_TABLE);
+    }
+    else if (JAVA_OTA_DATABASE_NAME == aStorageName)
+    {
+        sqlStatement.append("ID FROM ");
+        sqlStatement.append(OTA_STATUS_TABLE);
+    }
+    else
+    {
+        // External DB initialisation is not supported.
+        // returning true skips other checks.
+        return true;
+    }
+
+    sqlStatement.append(";");
+
+    auto_ptr<HBufC> sqlDes(stringToDes(sqlStatement.c_str()));
+
+    TInt err = mDatabase.Exec(sqlDes->Des());
+
+    if (err >= 0)
+    {
+        result = true;
+    }
+    else
+    {
+        WLOG1(EJavaStorage, "Database is not initialized: %d", err);
+    }
+
+    return result;
+}
+
+void JavaDataAccessImpl::initializeDatabase(const string& aStorageName)
+throw(JavaStorageException)
+{
+    JELOG2(EJavaStorage);
+
+    if (JAVA_DATABASE_NAME == aStorageName
+            && !isDBInitialized(aStorageName))
+    {
+        auto_ptr<HBufC> sqlDes(stringToDes(APPLICATION_PACKAGE));
+        LOG(EJavaStorage, EInfo, "Creating APPLICATION PACKAGE");
+        createTable(sqlDes->Des());
+
+        sqlDes.reset(stringToDes(APPLICATION));
+        LOG(EJavaStorage, EInfo, "Creating APPLICATION");
+        createTable(sqlDes->Des());
+
+        sqlDes.reset(stringToDes(APPLICATION_PACKAGE_ATTRIBUTES));
+        LOG(EJavaStorage, EInfo, "Creating APPLICATION_PACKAGE_ATTRIBUTES");
+        createTable(sqlDes->Des());
+
+        sqlDes.reset(stringToDes(MIDP_PACKAGE));
+        LOG(EJavaStorage, EInfo, "Creating MIDP_PACKAGE");
+        createTable(sqlDes->Des());
+
+        sqlDes.reset(stringToDes(MIDP_PERMISSIONS));
+        LOG(EJavaStorage, EInfo, "Creating MIDP_PERMISSIONS");
+        createTable(sqlDes->Des());
+
+        sqlDes.reset(stringToDes(MIDP_FUNC_GRP_SETTINGS));
+        LOG(EJavaStorage, EInfo, "Creating MIDP_FUNC_GRP_SETTINGS");
+        createTable(sqlDes->Des());
+
+        sqlDes.reset(stringToDes(PUSH_REGISTRATIONS));
+        LOG(EJavaStorage, EInfo, "Creating PUSH_REGISTRATIONS");
+        createTable(sqlDes->Des());
+
+        sqlDes.reset(stringToDes(ALARM_REGISTRATIONS));
+        LOG(EJavaStorage, EInfo, "Creating ALARM_REGISTRATIONS");
+        createTable(sqlDes->Des());
+
+        sqlDes.reset(stringToDes(RUNTIME_SETTINGS));
+        LOG(EJavaStorage, EInfo, "Creating RUNTIME_SETTINGS");
+        createTable(sqlDes->Des());
+
+        sqlDes.reset(stringToDes(PREINSTALL));
+        LOG(EJavaStorage, EInfo, "Creating PREINSTALL");
+        createTable(sqlDes->Des());
+    }
+    else if (JAVA_OTA_DATABASE_NAME == aStorageName
+             && !isDBInitialized(aStorageName))
+    {
+        auto_ptr<HBufC> sqlDes(stringToDes(OTA_STATUS));
+        LOG(EJavaStorage, EInfo, "Creating OTA_STATUS");
+        createTable(sqlDes->Des());
+    }
+}
+
+OS_EXPORT void JavaDataAccessImpl::close(const string& /*aHeaders*/,
+        CommsMessage& aReceivedMessage)
+throw(JavaStorageException)
+{
+    JELOG2(EJavaStorage);
+    int status = OK;
+
+    // If active transaction while closing connection. Rollback is tried.
+    if (mHavingTransaction)
+    {
+        WLOG(EJavaStorage,
+             "Active transaction while closing connection. Rollback.");
+
+        _LIT(KRollbackStatement, "ROLLBACK;");
+        TInt err = mDatabase.Exec(KRollbackStatement);
+    }
+
+    mDatabase.Close();
+    mConnOpen = false;
+    mHavingTransaction = false;
+
+    aReceivedMessage<<status;
+    aReceivedMessage<<mSessionId;
+}
+
+OS_EXPORT void JavaDataAccessImpl::execute(const string& aHeaders,
+        const wstring& aSqlStatement,
+        CommsMessage& aReceivedMessage)
+throw(JavaStorageException)
+{
+    JELOG2(EJavaStorage);
+
+    int status = OK;
+    wstring resultData;
+
+    // First char contains msgId len
+    int msgIdLen = JavaCommonUtils::stringToInt(aHeaders.substr(0, 1));
+    // Next chars contain msgId
+    int msgId = JavaCommonUtils::stringToInt(aHeaders.substr(1, msgIdLen));
+
+    auto_ptr<HBufC> sqlStatement(HBufC16::New(aSqlStatement.size() + 1));
+
+    if (!sqlStatement.get())
+    {
+        throw JavaStorageException(KErrNoMemory,
+                                   "Cannot allocate statement Buffer",
+                                   __FILE__, __FUNCTION__, __LINE__);
+    }
+
+    TPtr16 statementPtr(sqlStatement->Des());
+    statementPtr = (const TUint16*)aSqlStatement.c_str();
+
+    // ###################### TEMP ############################################
+    // LOG1WSTR(EJavaStorage, EInfo, "Sql statement: %s", aSqlStatement);
+    // ####################### END OF TEMP ####################################
+
+    switch (msgId)
+    {
+    case JavaStorageMessage::EStartTransaction:
+    {
+        TInt err = mDatabase.Exec(sqlStatement->Des());
+        status = err;
+        resultData = L"OK";
+
+        if (status < 0)
+        {
+            mHavingTransaction = false;
+        }
+        else
+        {
+            mHavingTransaction = true;
+        }
+        break;
+    }
+    case JavaStorageMessage::ECommit:
+    case JavaStorageMessage::ERollback:
+    {
+        TInt err = mDatabase.Exec(sqlStatement->Des());
+        status = err;
+        resultData = L"OK";
+
+        if (status >= 0)
+        {
+            mHavingTransaction = false;
+        }
+        break;
+    }
+    case JavaStorageMessage::EWrite:
+    case JavaStorageMessage::ECreateTable:
+    case JavaStorageMessage::EUpdate:
+    case JavaStorageMessage::EAppendTable:
+    {
+        TInt err = mDatabase.Exec(sqlStatement->Des());
+        status = err;
+        resultData = L"OK";
+        break;
+    }
+    case JavaStorageMessage::ERemove:
+    {
+        TInt err = mDatabase.Exec(sqlStatement->Des());
+        status = err;
+
+        if (0 <= status)
+        {
+            // Add affected row amount
+            resultData = JavaCommonUtils::intToWstring(status);
+        }
+        break;
+    }
+    case JavaStorageMessage::ERead:
+    case JavaStorageMessage::ESearch:
+    {
+        RSqlStatement statement;
+        TInt err = statement.Prepare(mDatabase, sqlStatement->Des());
+
+        if (err < 0)
+        {
+            ELOG1(EJavaStorage, "Prepare error: %d", err);
+            status = err;
+            statement.Close();
+            break;
+        }
+
+        while ((err = statement.Next()) == KSqlAtRow)
+        {
+            resultData.append(L";#\n;");
+
+            for (int i = 0; i < statement.ColumnCount(); i++)
+            {
+                TSqlColumnType colType = statement.ColumnType(i);
+
+                if (colType != ESqlNull)
+                {
+                    wstring colValue = L"";
+                    columnValue(i, statement, colType, colValue);
+
+                    wstring colName = L"";
+                    columnName(i, statement, colName);
+                    resultData.append(colName).append(L"=")
+                    .append(colValue).append(L";\n;");
+                }
+            }
+        }
+
+        if (err != KSqlAtEnd)
+        {
+            ELOG1(EJavaStorage,
+                  "Error during statement execution: %d", err);
+        }
+
+        status = err;
+
+        if (resultData.size() == 0)
+        {
+            resultData = L"OK"; // Indicate no match found.
+        }
+
+        statement.Close();
+        break;
+    }
+    default:
+    {
+        LOG1(EJavaStorage, EInfo, "Unknown command: %d", msgId);
+        break;
+    }
+    }
+
+    if (status < 0)
+    {
+        ELOG1WSTR(EJavaStorage, "ErrorStmt: %s", aSqlStatement);
+        TPtrC errMsg = mDatabase.LastErrorMessage();
+        auto_ptr<HBufC16> tempBuf(HBufC16::New(errMsg.Size() + 1));
+
+        if (!tempBuf.get())
+        {
+            throw JavaStorageException(
+                KErrNoMemory, "Cannot allocate errorMsg buffer",
+                __FILE__, __FUNCTION__, __LINE__);
+        }
+
+        TPtr16 tempBufPtr(tempBuf->Des());
+        tempBufPtr.Append(errMsg);
+        wstring tempStr(desToWstring(tempBufPtr));
+        resultData = tempStr;
+
+        if (resultData.size() == 0)
+        {
+            resultData = L"No error description available";
+        }
+        ELOG1WSTR(EJavaStorage, "EMsg: %s", resultData);
+    }
+
+    aReceivedMessage<<status;
+    aReceivedMessage<<resultData;
+}
+
+void JavaDataAccessImpl::openDatabase(const string& aStorageName)
+throw(JavaStorageException)
+{
+    JELOG2(EJavaStorage);
+
+    auto_ptr<HBufC> dbName(0);
+    bool isDefaultDB = false;
+
+    if (JAVA_DATABASE_NAME == aStorageName
+            || JAVA_OTA_DATABASE_NAME == aStorageName)
+    {
+        TUid tempUid = TUid::Uid(KJavaCaptainUid);
+        java::util::Uid uid;
+        TUidToUid(tempUid, uid);
+        const char* tempStr = JavaCommonUtils::wstringToUtf8(uid.toString());
+        string uidStr(tempStr);
+        delete [] tempStr;
+        string tempName = "c:" + uidStr + aStorageName + ".db";
+
+        dbName.reset(stringToDes(tempName.c_str()));
+        isDefaultDB = true;
+    }
+    else
+    {
+        dbName.reset(stringToDes(aStorageName.c_str()));
+    }
+
+    if (KErrNone != mDatabase.Open(dbName->Des(), &KJavaDbTimeoutOption))
+    {
+        createDatabase(dbName->Des(), isDefaultDB);
+        initializeDatabase(aStorageName);
+    }
+
+    LOG1(EJavaStorage, EInfo, "Database '%s' opened", aStorageName.c_str());
+    mConnOpen = true;
+}
+
+void JavaDataAccessImpl::createDatabase(const TDesC& aDbName, bool aIsDefault)
+throw(JavaStorageException)
+{
+    JELOG2(EJavaStorage);
+    mDatabase.Close();
+
+    TInt err = KErrNone;
+
+    if (aIsDefault)
+    {
+        TSecurityPolicy defaultPolicy;
+        RSqlSecurityPolicy securityPolicy;
+
+        securityPolicy.Create(defaultPolicy);
+
+        // Create similar security policy to all Java platform system databases.
+
+#ifdef RD_JAVA_S60_RELEASE_9_2_ONWARDS
+        TSecurityPolicy schemaPolicy(ECapabilityTrustedUI);
+        TSecurityPolicy writePolicy(ECapabilityTrustedUI);
+#else  // RD_JAVA_S60_RELEASE_9_2_ONWARDS
+        // Beta release must be run with lower capability set as
+        // SBE engine capability set cannot anymore be modified.
+        TSecurityPolicy schemaPolicy(ECapabilityWriteDeviceData);
+        TSecurityPolicy writePolicy(ECapabilityWriteDeviceData);
+#endif  // RD_JAVA_S60_RELEASE_9_2_ONWARDS
+
+        TSecurityPolicy readPolicy(TSecurityPolicy::EAlwaysPass);
+
+        securityPolicy.SetDbPolicy(RSqlSecurityPolicy::ESchemaPolicy,
+                                   schemaPolicy);
+        securityPolicy.SetDbPolicy(RSqlSecurityPolicy::EWritePolicy,
+                                   writePolicy);
+        securityPolicy.SetDbPolicy(RSqlSecurityPolicy::EReadPolicy, readPolicy);
+        err = mDatabase.Create(aDbName, securityPolicy);
+        securityPolicy.Close();
+    }
+    else
+    {
+        err = mDatabase.Create(aDbName);
+    }
+
+    if (KErrNone != err)
+    {
+        ELOG1(EJavaStorage, "Cannot create database: %d", err);
+
+        // LastErrorMessage cannot be called as create or open
+        // didn't succeeded.
+        mSessionId = "Database creation error";
+        mConnOpen = false;
+
+        throw JavaStorageException(err, mSessionId.c_str(),
+                                   __FILE__, __FUNCTION__, __LINE__);
+    }
+    mConnOpen = true;
+}
+
+void JavaDataAccessImpl::createTable(const TDesC& aStatement)
+throw(JavaStorageException)
+{
+    TInt err = mDatabase.Exec(aStatement);
+
+    if (err < 0)
+    {
+        ELOG1(EJavaStorage, "Table create failed: %d", err);
+        throw JavaStorageException(
+            EInvalidDataStructure,
+            "Table creation failed",
+            __FILE__,
+            __FUNCTION__,
+            __LINE__);
+    }
+}
+
+void JavaDataAccessImpl::columnName(int aIndex,
+                                    RSqlStatement& aStmt,
+                                    wstring& aColName)
+{
+    TPtrC16 columnNamePtr;
+    TInt err = aStmt.ColumnName(aIndex, columnNamePtr);
+
+    if (KErrNone != err)
+    {
+        WLOG1(EJavaStorage, "Get ColumnName: %d", err);
+    }
+
+    // Deep copy needed.
+    auto_ptr<HBufC16> colName(HBufC16::New(columnNamePtr.Length() + 1));
+
+    if (!colName.get())
+    {
+        throw JavaStorageException(KErrNoMemory,
+                                   "Cannot allocate column name buffer",
+                                   __FILE__, __FUNCTION__, __LINE__);
+    }
+
+    TPtr16 colName2Ptr(colName->Des());
+    colName2Ptr.Append(columnNamePtr);
+    wstring temp(desToWstring(colName2Ptr));
+    aColName = temp;
+}
+
+void JavaDataAccessImpl::columnValue(const int aIndex,
+                                     RSqlStatement& aStmt,
+                                     const TSqlColumnType aColumnType,
+                                     wstring& aColValue)
+{
+    // Only INT and STRING currently supported
+    if (ESqlInt == aColumnType)
+    {
+        TInt value = aStmt.ColumnInt(aIndex);
+        aColValue = JavaCommonUtils::intToWstring(value);
+    }
+    else
+    {
+        // Deep copy needed.
+        auto_ptr<HBufC16> column(HBufC16::New(aStmt.ColumnSize(aIndex) + 1));
+
+        if (!column.get())
+        {
+            throw JavaStorageException(KErrNoMemory,
+                                       "Cannot allocate column value buffer",
+                                       __FILE__, __FUNCTION__, __LINE__);
+        }
+
+        TPtr16 columnPtr(column->Des());
+        TInt colErr = aStmt.ColumnText(aIndex, columnPtr);
+
+        wstring temp(desToWstring(columnPtr));
+        aColValue = temp;
+    }
+}