Implement Service Refactoring

<UserStory> 1958: Service Refactoring </UserStory>
UserStory #1958
<Changes>

1. Added DataStoreLockGuard.h include to project file and InventoryManagementService
   for thread-safe datastore operations.

2. Enhanced DataStore::getUsers to load SerializedUser records, refresh cache,
   and attach notifications with recipient validation.

3. Enhanced DataStore::getInventoryItems to load SerializedInventoryItem records
   and refresh cache for tracked inventory items.

4. Refactored InventoryManagementService::sendLowStockAlerts to use tracked
   inventory and user maps with DataStoreLockGuard, ensuring safe access.

5. Removed legacy observer management, load/save inventory items, and related
   persistence functions from InventoryManagementService.

6. Updated InventoryManagementService::addInventoryItem to insert new records
   into tracked inventory map and persist changes via saveInventoryItems.

7. Updated InventoryManagementService::addInventoryItemStock to validate item
   existence, update quantity, mark record as MODIFIED, and persist changes.

8. Refactored InventoryManagementService::getInventoryItems to return object
   map extracted from tracked records with DataStoreLockGuard.

9. Updated InventoryManagementService::removeInventoryItem to validate item ID,
   mark state as INACTIVE, set record state to MODIFIED, and persist changes.

10. Updated InventoryManagementService::getInventoryItem to safely retrieve
    inventory items from tracked records with error handling.

</Changes>

<Test>

N/A

</Test>

<Review>

Sreeja Reghukumar

</Review>
This commit is contained in:
Avinash Rajesh
2026-06-12 18:29:10 +05:30
parent b98062d45c
commit f0c7d27e6c
5 changed files with 107 additions and 124 deletions
@@ -157,6 +157,7 @@
<ClInclude Include="core\patterns\Observer.h" /> <ClInclude Include="core\patterns\Observer.h" />
<ClInclude Include="core\patterns\Subject.h" /> <ClInclude Include="core\patterns\Subject.h" />
<ClInclude Include="datastores\DataStore.h" /> <ClInclude Include="datastores\DataStore.h" />
<ClInclude Include="datastores\DataStoreLockGuard.h" />
<ClInclude Include="datastores\sharedmemory\FileHeader.h" /> <ClInclude Include="datastores\sharedmemory\FileHeader.h" />
<ClInclude Include="datastores\sharedmemory\MappingInfo.h" /> <ClInclude Include="datastores\sharedmemory\MappingInfo.h" />
<ClInclude Include="datastores\sharedmemory\RecordState.h" /> <ClInclude Include="datastores\sharedmemory\RecordState.h" />
@@ -228,6 +228,22 @@ Returns:
*/ */
util::Map<std::string, TrackedRecord<User>>& DataStore::getUsers() util::Map<std::string, TrackedRecord<User>>& DataStore::getUsers()
{ {
auto users = loadRecords<User, SerializedUser>(m_users);
refreshCache(m_userCache, users);
auto& notifications = getNotifications();
int numberOfNotifications = m_notificationCache.getSize();
for (int index = 0; index < numberOfNotifications; index++)
{
Notification* notification = notifications.getValueAt(index).data;
const std::string& recipientUserId = notification->getRecipientUserId();
int userIndex = m_userCache.find(recipientUserId);
if (userIndex == -1)
{
throw std::runtime_error("Invalid recipient user ID");
}
User* user = m_userCache.getValueAt(userIndex).data;
user->addNotification(notification);
}
return m_userCache; return m_userCache;
} }
@@ -280,6 +296,8 @@ Returns:
*/ */
util::Map<std::string, TrackedRecord<InventoryItem>>& DataStore::getInventoryItems() util::Map<std::string, TrackedRecord<InventoryItem>>& DataStore::getInventoryItems()
{ {
auto inventoryItems = loadRecords<InventoryItem, SerializedInventoryItem>(m_inventoryItems);
refreshCache(m_inventoryItemCache, inventoryItems);
return m_inventoryItemCache; return m_inventoryItemCache;
} }
@@ -419,6 +437,7 @@ Returns:
*/ */
void DataStore::saveInventoryItems() void DataStore::saveInventoryItems()
{ {
saveRecords<InventoryItem, SerializedInventoryItem>(m_inventoryItems, m_inventoryItemCache);
} }
/* /*
@@ -0,0 +1,28 @@
/*
File: DataStoreLockGuard.h
Description: Defines the DataStoreLockGuard class used to manage DataStore
locking and unlocking automatically within a scope.
Author: Trenser
Date: 12-June-2026
*/
#pragma once
#include "DataStore.h"
class DataStoreLockGuard
{
public:
explicit DataStoreLockGuard(DataStore& dataStore)
: m_dataStore(dataStore)
{
m_dataStore.lockDataStore();
}
~DataStoreLockGuard()
{
m_dataStore.unlockDataStore();
}
DataStoreLockGuard(const DataStoreLockGuard&) = delete;
DataStoreLockGuard& operator=(const DataStoreLockGuard&) = delete;
private:
DataStore& m_dataStore;
};
@@ -19,7 +19,7 @@ Date: 22-May-2026
#include "User.h" #include "User.h"
#include "Utility.h" #include "Utility.h"
#include "Vector.h" #include "Vector.h"
#include "DataStoreLockGuard.h"
util::Map<std::string, User*> InventoryManagementService::m_observers{}; util::Map<std::string, User*> InventoryManagementService::m_observers{};
@@ -58,18 +58,19 @@ Returns:
*/ */
void InventoryManagementService::sendLowStockAlerts() void InventoryManagementService::sendLowStockAlerts()
{ {
auto& inventoryItems = m_dataStore.getInventoryItems(); DataStoreLockGuard lock(m_dataStore);
if (inventoryItems.isEmpty()) auto& trackedInventoryItemsMap = m_dataStore.getInventoryItems();
auto& trackedUserMap = m_dataStore.getUsers();
if (trackedInventoryItemsMap.isEmpty())
{ {
return; return;
} }
int inventoryItemsSize = inventoryItems.getSize(); int inventoryItemsSize = trackedInventoryItemsMap.getSize();
auto& usersMap = m_dataStore.getUsers(); int usersMapSize = trackedUserMap.getSize();
int usersMapSize = usersMap.getSize();
util::Vector<User*> adminUsers; util::Vector<User*> adminUsers;
for (int index = 0; index < usersMapSize; index++) for (int index = 0; index < usersMapSize; index++)
{ {
User* user = usersMap.getValueAt(index); User* user = trackedUserMap.getValueAt(index).data;
if (user->getUserType() == util::UserType::ADMIN) if (user->getUserType() == util::UserType::ADMIN)
{ {
adminUsers.push_back(user); adminUsers.push_back(user);
@@ -82,7 +83,7 @@ void InventoryManagementService::sendLowStockAlerts()
} }
for (int index = 0; index < inventoryItemsSize; index++) for (int index = 0; index < inventoryItemsSize; index++)
{ {
InventoryItem* inventoryItem = inventoryItems.getValueAt(index); InventoryItem* inventoryItem = trackedInventoryItemsMap.getValueAt(index).data;
if (inventoryItem && inventoryItem->getQuantity() < config::threshold::INVENTORY_LOW_STOCK_THRESHOLD) if (inventoryItem && inventoryItem->getQuantity() < config::threshold::INVENTORY_LOW_STOCK_THRESHOLD)
{ {
sendLowStockAlertsToAdmins(*this, inventoryItem, adminUsers); sendLowStockAlertsToAdmins(*this, inventoryItem, adminUsers);
@@ -90,95 +91,6 @@ void InventoryManagementService::sendLowStockAlerts()
} }
} }
/*
Function: getObserverIDs
Description: Retrieves the IDs of all observers currently attached to the
InventoryManagementService.
Parameters:
- None
Returns:
- util::Vector<std::string>: Vector of observer user IDs
*/
util::Vector<std::string> InventoryManagementService::getObserverIDs()
{
util::Vector<std::string> observerIDs;
int numberOfObservers = m_observers.getSize();
for (int index = 0; index < numberOfObservers; index++)
{
User* observer = m_observers.getValueAt(index);
if (observer)
{
observerIDs.push_back(observer->getId());
}
}
return observerIDs;
}
/*
Function: loadInventoryItems
Description: Loads inventory items from persistent storage into the datastore.
Uses FileManager to deserialize inventory items from the configured file.
Parameters:
- None
Returns:
- void
*/
void InventoryManagementService::loadInventoryItems()
{
util::FileManager<InventoryItem> inventoryItemFileManager(config::file::INVENTORYITEM_FILE);
auto& inventoryItems = m_dataStore.getInventoryItems();
auto inventoryItemsMap = inventoryItemFileManager.load();
int numberOfInventoryItems = inventoryItemsMap.getSize();
for (int index = 0; index < numberOfInventoryItems; index++)
{
inventoryItems[inventoryItemsMap.getKeyAt(index)] = inventoryItemsMap.getValueAt(index);
}
}
/*
Function: saveInventoryItems
Description: Saves inventory items from the datastore to persistent storage.
Uses FileManager to serialize inventory items into the configured file.
Parameters:
- None
Returns:
- void
*/
void InventoryManagementService::saveInventoryItems()
{
util::FileManager<InventoryItem> inventoryItemFileManager(config::file::INVENTORYITEM_FILE);
auto& inventoryItems = m_dataStore.getInventoryItems();
inventoryItemFileManager.save(inventoryItems);
}
/*
Function: loadObservers
Description: Loads observer IDs from persistent storage and attaches corresponding
users as observers to the InventoryManagementService.
Parameters:
- None
Returns:
- void
*/
void InventoryManagementService::loadObservers()
{
util::loadObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this, m_dataStore);
}
/*
Function: saveObservers
Description: Saves the current observer IDs of the InventoryManagementService
to persistent storage for future retrieval.
Parameters:
- None
Returns:
- void
*/
void InventoryManagementService::saveObservers()
{
util::saveObservers(config::file::INVENTORYMANAGEMENTOBSERVERS, this);
}
/* /*
Function: addInventoryItem Function: addInventoryItem
Description: Creates a new inventory item using the Factory and inserts it Description: Creates a new inventory item using the Factory and inserts it
@@ -190,8 +102,11 @@ Return type: void
*/ */
void InventoryManagementService::addInventoryItem(const std::string& partName, int quantity, double price) void InventoryManagementService::addInventoryItem(const std::string& partName, int quantity, double price)
{ {
DataStoreLockGuard lock(m_dataStore);
auto& trackedInventoryItemMap = m_dataStore.getInventoryItems();
InventoryItem* newItem = Factory::getObject<InventoryItem>(partName, quantity, price); InventoryItem* newItem = Factory::getObject<InventoryItem>(partName, quantity, price);
m_dataStore.getInventoryItems().insert(newItem->getId(), newItem); trackedInventoryItemMap.insert(newItem->getId(), util::createNewRecord(newItem));
m_dataStore.saveInventoryItems();
} }
/* /*
@@ -203,16 +118,22 @@ Return type: void
*/ */
void InventoryManagementService::addInventoryItemStock(const std::string& selectedItemId, int quantity) void InventoryManagementService::addInventoryItemStock(const std::string& selectedItemId, int quantity)
{ {
int index = m_dataStore.getInventoryItems().find(selectedItemId); DataStoreLockGuard lock(m_dataStore);
if (index != -1) auto& trackedInventoryItemMap = m_dataStore.getInventoryItems();
{ int index = trackedInventoryItemMap.find(selectedItemId);
InventoryItem* item = m_dataStore.getInventoryItems().getValueAt(index); if (index == -1)
if (item != nullptr) {
{ throw std::runtime_error("Inventory update failed: Item ID '" + selectedItemId + "' not found.");
int totalQuantity = item->getQuantity() + quantity; }
item->setQuantity(totalQuantity); InventoryItem* item = trackedInventoryItemMap.getValueAt(index).data;
} if (item == nullptr)
} {
throw std::runtime_error("Inventory update failed. Item does not exist.\n");
}
int totalQuantity = item->getQuantity() + quantity;
item->setQuantity(totalQuantity);
trackedInventoryItemMap.getValueAt(index).state = RecordState::MODIFIED;
m_dataStore.saveInventoryItems();
} }
/* /*
@@ -223,7 +144,10 @@ Return type: util::Map<std::string, InventoryItem*>
*/ */
util::Map<std::string, InventoryItem*> InventoryManagementService::getInventoryItems() util::Map<std::string, InventoryItem*> InventoryManagementService::getInventoryItems()
{ {
return m_dataStore.getInventoryItems(); DataStoreLockGuard lock(m_dataStore);
auto& trackedInventoryItemMap = m_dataStore.getInventoryItems();
auto inventoryMap = util::getObjects(trackedInventoryItemMap);
return inventoryMap;
} }
/* /*
@@ -234,15 +158,21 @@ Return type: void
*/ */
void InventoryManagementService::removeInventoryItem(const std::string& inventoryItemID) void InventoryManagementService::removeInventoryItem(const std::string& inventoryItemID)
{ {
int index = m_dataStore.getInventoryItems().find(inventoryItemID); DataStoreLockGuard lock(m_dataStore);
if (index != -1) auto& trackedInventoryItemMap = m_dataStore.getInventoryItems();
{ int index = trackedInventoryItemMap.find(inventoryItemID);
InventoryItem* item = m_dataStore.getInventoryItems().getValueAt(index); if (index == -1)
if (item != nullptr) {
{ throw std::runtime_error("Inventory removal failed: Item ID '" + inventoryItemID + "' not found.");
item->setState(util::State::INACTIVE); }
} InventoryItem* item = trackedInventoryItemMap.getValueAt(index).data;
} if (item == nullptr)
{
throw std::runtime_error("Inventory removal failed: Item ID does not exist.");
}
item->setState(util::State::INACTIVE);
trackedInventoryItemMap.getValueAt(index).state = RecordState::MODIFIED;
m_dataStore.saveInventoryItems();
} }
/* /*
@@ -253,12 +183,19 @@ Return type: InventoryItem*
*/ */
InventoryItem* InventoryManagementService::getInventoryItem(const std::string& inventoryItemID) InventoryItem* InventoryManagementService::getInventoryItem(const std::string& inventoryItemID)
{ {
int index = m_dataStore.getInventoryItems().find(inventoryItemID); DataStoreLockGuard lock(m_dataStore);
if (index != -1) auto& trackedInventoryItemMap = m_dataStore.getInventoryItems();
int index = trackedInventoryItemMap.find(inventoryItemID);
if (index == -1)
{ {
return m_dataStore.getInventoryItems().getValueAt(index); return nullptr;
} }
return nullptr; InventoryItem* inventoryItem = trackedInventoryItemMap.getValueAt(index).data;
if (inventoryItem == nullptr)
{
throw std::runtime_error("Item ID does not exist.");
}
return inventoryItem;
} }
/* /*
@@ -33,8 +33,6 @@ public:
void sendNotification(User* user, const std::string& title, const std::string& message) override; void sendNotification(User* user, const std::string& title, const std::string& message) override;
void attach(User* user) override; void attach(User* user) override;
void detach(User* user) override; void detach(User* user) override;
void loadInventoryItems();
void saveInventoryItems();
void loadObservers(); void loadObservers();
void saveObservers(); void saveObservers();
}; };