javacommons/javastorage/src/client/messagedispatcher.cpp
changeset 21 2a9601315dfc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/javastorage/src/client/messagedispatcher.cpp	Mon May 03 12:27:20 2010 +0300
@@ -0,0 +1,487 @@
+/*
+* 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:  MessageDispatcher
+*
+*/
+
+
+#include "commsmessage.h"
+#include "javacommonutils.h"
+#include "javadataaccess.h"
+#include "javastorageexception.h"
+#include "logger.h"
+#include "messagedispatcher.h"
+#include "statementutils.h"
+
+using namespace java::comms;
+using namespace java::storage;
+using namespace java::util;
+using namespace std;
+
+MessageDispatcher::MessageDispatcher()
+{
+    JELOG2(EJavaStorage);
+    mDataAccess.reset(JavaDataAccess::createInstance());
+    mUtils.reset(new StatementUtils());
+}
+
+MessageDispatcher::~MessageDispatcher()
+{
+}
+
+std::string MessageDispatcher::createAndSendMessage(
+    JavaStorageMessage::MessageIdentifier aMsgId,
+    const string& aHeaders,
+    const string& aDatabaseName)
+{
+    JELOG2(EJavaStorage);
+
+    string sessionID = "";
+    CommsMessage receivedMessage;
+    int statusCode = -1;
+
+    string headers = aHeaders;
+    createHeader(aMsgId, headers);
+
+    switch (aMsgId)
+    {
+    case JavaStorageMessage::EOpen:
+    {
+        mDataAccess->open(headers, aDatabaseName, receivedMessage);
+
+        receivedMessage>>statusCode;
+
+        if (statusCode >= 0)
+        {
+            receivedMessage>>sessionID;
+            LOG1(EJavaStorage, EInfo, "Received sessionID: %s",
+                 sessionID.c_str());
+        }
+        break;
+    }
+    case JavaStorageMessage::EClose:
+    {
+        mDataAccess->close(headers, receivedMessage);
+        receivedMessage>>statusCode;
+        break;
+    }
+    case JavaStorageMessage::EStartTransaction:
+    {
+        mDataAccess->execute(headers, L"BEGIN;", receivedMessage);
+        receivedMessage>>statusCode;
+        break;
+    }
+    case JavaStorageMessage::ECommit:
+    {
+        mDataAccess->execute(headers, L"COMMIT;", receivedMessage);
+        receivedMessage>>statusCode;
+        break;
+    }
+    case JavaStorageMessage::ERollback:
+    {
+        mDataAccess->execute(headers, L"ROLLBACK;", receivedMessage);
+        receivedMessage>>statusCode;
+        break;
+    }
+    default:
+    {
+        ELOG1(EJavaStorage, "Unknown command: %d", aMsgId);
+        throw JavaStorageException(aMsgId, "Unknown message",
+                                   __FILE__, __FUNCTION__, __LINE__);
+    }
+    }
+
+    if (statusCode < 0)
+    {
+        string errorMessage = "";
+        readErrorMessage(receivedMessage, errorMessage);
+        throw JavaStorageException(statusCode, errorMessage.c_str(),
+                                   __FILE__, __FUNCTION__, __LINE__);
+    }
+
+    return sessionID;
+}
+
+int MessageDispatcher::createAndSendMessage(
+    JavaStorageMessage::MessageIdentifier aMsgId,
+    const string& aHeaders,
+    const string& identifier,
+    const JavaStorageApplicationEntry_t& aEntry)
+{
+    JELOG2(EJavaStorage);
+
+    CommsMessage receivedMessage;
+    int statusCode = -1;
+    int retVal = -1;
+
+    string headers = aHeaders;
+    createHeader(aMsgId, headers);
+
+    wstring insertion(L", ");
+
+    switch (aMsgId)
+    {
+    case JavaStorageMessage::EWrite:
+    {
+        wstring sqlStatement = L"";
+        mUtils->createWriteStatement(
+            aEntry, identifier, insertion, sqlStatement);
+        mDataAccess->execute(headers, sqlStatement, receivedMessage);
+
+        receivedMessage>>statusCode;
+        break;
+    }
+    case JavaStorageMessage::ERead:
+    {
+        // Contains only one entry. It is already checked.
+        JavaStorageApplicationEntry_t::const_iterator iter = aEntry.begin();
+
+        wstring sqlStatement = L"SELECT * FROM ";
+        sqlStatement.append(
+            JavaCommonUtils::utf8ToWstring(identifier.c_str()));
+        sqlStatement.append(L" WHERE ID = '")
+        .append((*iter).entryValue()).append(L"';");
+
+        mDataAccess->execute(headers, sqlStatement, receivedMessage);
+
+        receivedMessage>>statusCode;
+
+        if (statusCode >= 0)
+        {
+            // Const cast required. This prevent need to create yet another
+            // createAndSend subroutine.
+            JavaStorageApplicationEntry_t& temp =
+                const_cast<JavaStorageApplicationEntry_t&>(aEntry);
+
+            // Value was added by the API so remove that it does not exists
+            // in the response twice.
+            temp.clear();
+            populateEntry(receivedMessage, temp);
+        }
+        break;
+    }
+    case JavaStorageMessage::ERemove:
+    {
+        wstring sqlStatement = L"DELETE FROM ";
+
+        sqlStatement.append(
+            JavaCommonUtils::utf8ToWstring(identifier.c_str()));
+
+        if (aEntry.size() > 0)
+        {
+            mUtils->createWhereStatement(aEntry, sqlStatement);
+        }
+        else    // Delete whole table contents.
+        {
+            sqlStatement.append(L";");
+        }
+        mDataAccess->execute(headers, sqlStatement, receivedMessage);
+
+        receivedMessage>>statusCode;
+
+        if (statusCode >= 0)
+        {
+            wstring temp = L"";
+            receivedMessage>>temp;
+            // How many entries removed i.e. rows removed.
+            retVal = JavaCommonUtils::wstringToInt(temp);
+        }
+        break;
+    }
+    case JavaStorageMessage::ECreateTable:
+    {
+        wstring sqlStatement = L"";
+        mUtils->createTableStatement(
+            aEntry, identifier, insertion, sqlStatement);
+        mDataAccess->execute(headers, sqlStatement, receivedMessage);
+        receivedMessage>>statusCode;
+        break;
+    }
+    case JavaStorageMessage::EAppendTable:
+    {
+        // NOTE: SQLite supports adding only one column at the time.
+        // For this reason several calls need to be executed.
+
+        wstring prefix = L"ALTER TABLE ";
+
+        prefix.append(
+            JavaCommonUtils::utf8ToWstring(identifier.c_str()));
+
+        // Define added columns
+        // ID will always be primary key
+        prefix.append(L" ADD ");
+
+        JavaStorageApplicationEntry_t::const_iterator colIter;
+
+        for (colIter = aEntry.begin(); colIter != aEntry.end(); colIter++)
+        {
+            if ((*colIter).entryName() == L"")
+            {
+                throw JavaStorageException(EInvalidDataStructure,
+                                           "Column name not defined",
+                                           __FILE__, __FUNCTION__, __LINE__);
+            }
+
+            wstring sqlStatement = prefix;
+            sqlStatement.append((*colIter).entryName());
+
+            if (JavaStorageEntry::STRING == (*colIter).entryType())
+            {
+                sqlStatement.append(L" varchar");
+            }
+            else if (JavaStorageEntry::INT == (*colIter).entryType())
+            {
+                sqlStatement.append(L" int");
+            }
+            else
+            {
+                ELOG(EJavaStorage, "Unknown column type");
+                throw JavaStorageException(EInvalidDataStructure,
+                                           "Unknown column type",
+                                           __FILE__, __FUNCTION__, __LINE__);
+            }
+            sqlStatement.append(L";");
+
+            mDataAccess->execute(headers, sqlStatement, receivedMessage);
+
+            receivedMessage>>statusCode;
+
+            if (statusCode < 0)
+            {
+                break;  // stop execution on first error.
+            }
+            else
+            {
+                // Reset for next round
+                receivedMessage.reset();
+            }
+        }
+        break;
+    }
+    default:
+    {
+        ELOG1(EJavaStorage, "Unknown command: %d", aMsgId);
+        throw JavaStorageException(aMsgId, "Unknown message",
+                                   __FILE__, __FUNCTION__, __LINE__);
+    }
+    }
+
+    if (statusCode < 0)
+    {
+        string errorMessage = "";
+        readErrorMessage(receivedMessage, errorMessage);
+        throw JavaStorageException(statusCode, errorMessage.c_str(),
+                                   __FILE__, __FUNCTION__, __LINE__);
+    }
+    return retVal;
+}
+
+void MessageDispatcher::handleSearch(
+    JavaStorageMessage::MessageIdentifier aMsgId,
+    const string& aHeaders,
+    const string& aTableName,
+    const JavaStorageApplicationEntry_t& aEntry,
+    JavaStorageApplicationList_t& aAppList
+)
+{
+    int statusCode = -1;
+    CommsMessage receivedMessage;
+
+    string headers = aHeaders;
+    createHeader(aMsgId, headers);
+
+    wstring sqlStatement = L"";
+    mUtils->createSearchStatement(aEntry, aTableName, sqlStatement);
+    mDataAccess->execute(headers, sqlStatement, receivedMessage);
+
+    receivedMessage>>statusCode;
+
+    if (statusCode >= 0)
+    {
+        populateEntry(receivedMessage, aAppList);
+    }
+    else
+    {
+        string errorMessage = "";
+        readErrorMessage(receivedMessage, errorMessage);
+        throw JavaStorageException(statusCode, errorMessage.c_str(),
+                                   __FILE__, __FUNCTION__, __LINE__);
+    }
+}
+
+void MessageDispatcher::handleUpdate(
+    JavaStorageMessage::MessageIdentifier aMsgId,
+    const string& aHeaders,
+    const string& identifier,
+    const JavaStorageApplicationEntry_t& aUpdateEntry,
+    const JavaStorageApplicationEntry_t& aMatchEntry)
+{
+    int statusCode = -1;
+    CommsMessage receivedMessage;
+    string headers = aHeaders;
+    createHeader(aMsgId, headers);
+
+    wstring sqlStatement = L"";
+    mUtils->createUpdateStatement(
+        aUpdateEntry, aMatchEntry, identifier, sqlStatement);
+
+    mDataAccess->execute(headers, sqlStatement, receivedMessage);
+    receivedMessage>>statusCode;
+
+    if (statusCode < 0)
+    {
+        string errorMessage = "";
+        readErrorMessage(receivedMessage, errorMessage);
+        throw JavaStorageException(statusCode, errorMessage.c_str(),
+                                   __FILE__, __FUNCTION__, __LINE__);
+    }
+}
+
+void MessageDispatcher::populateEntry(CommsMessage& aReceivedMessage,
+                                      JavaStorageApplicationEntry_t& aEntry)
+{
+    JELOG2(EJavaStorage);
+
+    wstring data;
+    aReceivedMessage>>data;
+
+    wstring::size_type startIdx = 0;
+    wstring::size_type endIdx = 0;
+    wstring appDelim = L";#\n;";
+    wstring attrDelim = L";\n;";
+
+    // Skipp app delimiter
+    if (data.find(appDelim) == 0)
+    {
+        startIdx = appDelim.size();
+        endIdx = startIdx;
+    }
+
+    // This method reads only one storage row. If multiple ones are given
+    // they are ignored.
+    if ((endIdx = data.find(appDelim, startIdx)) != string::npos)
+    {
+        WLOG(EJavaStorage, "Removing multiple app occurrences");
+        data = data.substr(0, endIdx);
+    }
+
+    // Reset counter
+    endIdx = startIdx;
+
+    wstring nameDelim = L"=";
+
+    while (string::npos != startIdx || string::npos != endIdx)
+    {
+        // Read name
+        endIdx = data.find(nameDelim, startIdx);
+        if (endIdx == string::npos) break;    // Not found
+
+        wstring name = data.substr(startIdx, (endIdx - startIdx));
+
+        // Read value. Skip name and delimiter
+        startIdx = endIdx + 1;
+        endIdx = data.find(attrDelim, startIdx);
+        if (endIdx == string::npos) break;    // Not found
+
+        wstring value = L"";
+
+        if (endIdx != startIdx)
+        {
+            value = data.substr(startIdx, (endIdx - startIdx));
+        }
+        // else empty value.
+
+        JavaStorageEntry entry;
+        entry.setEntry(name, value);
+        aEntry.insert(entry);
+
+        // Skip value and delimiter
+        startIdx = endIdx + attrDelim.size();
+        if (startIdx == string::npos) break;    // Not found
+    }
+}
+
+void MessageDispatcher::populateEntry(CommsMessage& aReceivedMessage,
+                                      JavaStorageApplicationList_t& aAppList)
+{
+    JELOG2(EJavaStorage);
+
+    wstring data;
+    aReceivedMessage>>data;
+
+    // ################# TEMP #################################################
+    // LOG1WSTR(EJavaStorage, EInfo, "Response: %s", data);
+    // ################# END OF TEMP ##########################################
+
+    wstring appDelim = L";#\n;";
+
+    if (data.size() <= appDelim.size())
+    {
+        LOG(EJavaStorage, EInfo, "No entries to populate");
+        return;
+    }
+
+    wstring::size_type startIdx = appDelim.size();
+    wstring::size_type endIdx = startIdx;
+
+    // This does two if else less within while loop as its known string
+    // terminates always despite of column amount.
+    data.append(appDelim);
+
+    JavaStorageApplicationEntry_t appEntry;
+
+    do
+    {
+        endIdx = data.find(appDelim, startIdx);
+
+        if (endIdx == string::npos) break;    // No token found
+
+        wstring appString = data.substr(startIdx, (endIdx - startIdx));
+
+        CommsMessage oneApp;
+        oneApp<<appString;
+        populateEntry(oneApp, appEntry);
+
+        aAppList.push_back(appEntry);
+        appEntry.clear();
+
+        // Skip app delimiter
+        startIdx = endIdx + appDelim.size();
+    }
+    while (string::npos != startIdx && string::npos != endIdx);
+}
+
+void MessageDispatcher::createHeader(int aMsgId, string& aHeaders)
+{
+    // Add command ID that server can identify open action
+    string msgID = JavaCommonUtils::intToString(aMsgId);
+    string msgIDSize = JavaCommonUtils::intToString(msgID.size());
+    // Insert size which must be fit to one char.
+    aHeaders.insert(0, msgIDSize);
+    // Insert msgID
+    aHeaders.insert(1, msgID);
+}
+
+void MessageDispatcher::readErrorMessage(CommsMessage& aReceivedMessage,
+        string& aErrMsg)
+{
+    wstring wideErrorMsg;
+    aReceivedMessage>>wideErrorMsg;
+
+    char* errorMsg = JavaCommonUtils::wstringToUtf8(wideErrorMsg);
+    string errorMessage(errorMsg);
+    delete[] errorMsg;
+    aErrMsg = errorMessage;
+    ELOG1(EJavaStorage, "Error message %s", aErrMsg.c_str());
+}