--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/javastorage/src/client/messagedispatcher.cpp Tue Apr 27 16:30:29 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());
+}