diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj index 6a269f5..7c4bfd3 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem.vcxproj @@ -157,6 +157,7 @@ + diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp index 9bc1d86..487ecd5 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.cpp @@ -588,63 +588,37 @@ void Controller::configureNotifications(bool paymentNotifications, bool serviceN } /* -Function: loadSystemData -Description: Loads all system data from persistent storage into memory. - Invokes the respective management services to load users, inventory items, services, - combo packages, service bookings, job cards, invoices, and observers. +Function: initialize +Description: Initializes the system and run system checks to ensure critical configurations, such as verifying admin existence. Parameters: - None Returns: - - void + - bool */ -void Controller::loadSystemData() +bool Controller::initialize() { - m_userManagementService.loadUsers(); - m_inventoryManagementService.loadInventoryItems(); - m_serviceManagementService.loadServices(); - m_serviceManagementService.loadComboPackages(); - m_serviceManagementService.loadServiceBookings(); - m_serviceManagementService.loadJobCards(); - m_paymentManagementService.loadInvoices(); - m_serviceManagementService.loadObservers(); - m_paymentManagementService.loadObservers(); - m_inventoryManagementService.loadObservers(); -} + auto& dataStore = DataStore::getInstance(); -/* -Function: saveSystemData -Description: Saves all system data from memory back to persistent storage. - Invokes the respective management services to save users, inventory items, services, - combo packages, service bookings, job cards, invoices, and observers. -Parameters: - - None -Returns: - - void -*/ -void Controller::saveSystemData() -{ - m_userManagementService.saveUsers(); - m_inventoryManagementService.saveInventoryItems(); - m_serviceManagementService.saveServices(); - m_serviceManagementService.saveComboPackages(); - m_serviceManagementService.saveServiceBookings(); - m_serviceManagementService.saveJobCards(); - m_paymentManagementService.saveInvoices(); - m_serviceManagementService.saveObservers(); - m_paymentManagementService.saveObservers(); - m_inventoryManagementService.saveObservers(); -} - -/* -Function: runSystemChecks -Description: Runs system checks to ensure critical configurations, such as verifying admin existence. -Parameter: None -Return type: void -*/ -void Controller::runSystemChecks() -{ + if (!dataStore.initialize()) + { + return false; + } m_userManagementService.ensureAdminExists(); m_inventoryManagementService.sendLowStockAlerts(); m_paymentManagementService.sendPaymentReminders(); + return true; } +/* +Function: shutdown +Description: Shutdown the system, and do necessary cleanups +Parameters: + - None +Returns: + - void +*/ +void Controller::shutdown() +{ + auto& dataStore = DataStore::getInstance(); + dataStore.shutdown(); +} diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h index 35241a0..7ec1c30 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/controllers/Controller.h @@ -70,7 +70,6 @@ public: util::Vector getNotifications(); void deleteNotification(const std::string& notificationID); void configureNotifications(bool paymentNotifications, bool serviceNotifications); - void loadSystemData(); - void saveSystemData(); - void runSystemChecks(); + bool initialize(); + void shutdown(); }; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp index 1cade32..bda9ac0 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStore.cpp @@ -228,6 +228,22 @@ Returns: */ util::Map>& DataStore::getUsers() { + auto users = loadRecords(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; } @@ -241,6 +257,8 @@ Returns: */ util::Map>& DataStore::getNotifications() { + auto notifications = loadRecords(m_notifications); + refreshCache(m_notificationCache, notifications); return m_notificationCache; } @@ -371,6 +389,8 @@ Returns: */ void DataStore::saveUsers() { + saveRecords(m_users, m_userCache); + saveNotifications(); } /* @@ -383,6 +403,7 @@ Returns: */ void DataStore::saveNotifications() { + saveRecords(m_notifications, m_notificationCache); } /* diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStoreLockGuard.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStoreLockGuard.h new file mode 100644 index 0000000..2e04eb0 --- /dev/null +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/DataStoreLockGuard.h @@ -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; +}; \ No newline at end of file diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.cpp index 6a10c9f..4b151e3 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/datastores/sharedmemory/SharedMemory.cpp @@ -10,6 +10,7 @@ Created: 11-June-2026 */ #include "SharedMemory.h" +#include "Windows.h" #include "Config.h" /* diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp index 8ba68d0..3eeead8 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.cpp @@ -20,6 +20,9 @@ Date:19-May-2026 #include "UserManagementService.h" #include "Vector.h" #include "Validator.h" +#include "Utility.h" +#include "TrackedRecord.h" +#include "DataStoreLockGuard.h" /* Function: ensureAdminExists @@ -31,12 +34,13 @@ Return type: void */ void UserManagementService::ensureAdminExists() { + DataStoreLockGuard lock(m_dataStore); auto& usersMap = m_dataStore.getUsers(); int usersMapSize = usersMap.getSize(); bool isAdminFound = false; for (int index = 0; index < usersMapSize; index++) { - User* user = usersMap.getValueAt(index); + User* user = usersMap.getValueAt(index).data; if (user && user->getUserType() == util::UserType::ADMIN) { isAdminFound = true; @@ -73,7 +77,9 @@ void UserManagementService::createUser(const std::string& username, const std::s InventoryManagementService inventoryManagementService; PaymentManagementService paymentManagementService; ServiceManagementService serviceManagementService; - auto& usersMap = m_dataStore.getUsers(); + DataStoreLockGuard lock(m_dataStore); + auto& trackedUsersMap = m_dataStore.getUsers(); + auto usersMap = util::getObjects(trackedUsersMap); if (util::isUsernameDuplicate(username, usersMap)) { throw std::runtime_error("Username already exists"); @@ -87,13 +93,14 @@ void UserManagementService::createUser(const std::string& username, const std::s throw std::runtime_error("Phone already exists"); } User* newUser = Factory::getObject(username, password, name, phone, email, type); - usersMap.insert(newUser->getId(), newUser); + trackedUsersMap.insert(newUser->getId(), util::createNewRecord(newUser)); paymentManagementService.attach(newUser); serviceManagementService.attach(newUser); if (newUser->getUserType() == util::UserType::ADMIN) { inventoryManagementService.attach(newUser); } + m_dataStore.saveUsers(); } /* @@ -107,19 +114,24 @@ Return type: void */ void UserManagementService::updateUserDetails(const std::string& userID, const std::string& email, const std::string& phone) { - auto& usersMap = m_dataStore.getUsers(); - int index = usersMap.find(userID); + DataStoreLockGuard lock(m_dataStore); + auto& trackedUsersMap = m_dataStore.getUsers(); + auto usersMap = util::getObjects(trackedUsersMap); + int index = trackedUsersMap.find(userID); if (index == -1) { throw std::runtime_error("User does not exist!\n"); } - User* user = usersMap.getValueAt(index); + User* user = trackedUsersMap.getValueAt(index).data; + bool isModified = false; if (email != user->getEmail()) { if (util::isEmailDuplicate(email, usersMap)) { throw std::runtime_error("Email already exists!\n"); } + user->setEmail(email); + isModified = true; } if (phone != user->getPhone()) { @@ -127,9 +139,14 @@ void UserManagementService::updateUserDetails(const std::string& userID, const s { throw std::runtime_error("Phone number already exists!\n"); } + user->setPhone(phone); + isModified = true; + } + if (isModified) + { + trackedUsersMap.getValueAt(index).state = RecordState::MODIFIED; + m_dataStore.saveUsers(); } - user->setEmail(email); - user->setPhone(phone); } /* @@ -144,12 +161,13 @@ Throws: */ util::Vector UserManagementService::getUserNotifications(const std::string& userID) { - auto& usersMap = m_dataStore.getUsers(); - if (usersMap.find(userID) == -1) + DataStoreLockGuard lock(m_dataStore); + auto& trackedUsersMap = m_dataStore.getUsers(); + if (trackedUsersMap.find(userID) == -1) { throw std::runtime_error("No user found with given UserID"); } - User* user = usersMap[userID]; + User* user = trackedUsersMap[userID].data; if (user) { auto& notifications = user->getNotifications(); @@ -159,6 +177,7 @@ util::Vector UserManagementService::getUserNotifications(const st { notificationsVector.push_back(notifications.getValueAt(index)); } + m_dataStore.unlockDataStore(); return notificationsVector; } else @@ -169,97 +188,41 @@ util::Vector UserManagementService::getUserNotifications(const st /* Function: deleteNotification -Description: Deletes a specific notification associated with a given user ID. +Description: Marks a specific notification associated with a given user + as inactive. Parameters: - notificationID: The unique ID of the notification to be deleted. - userID: The unique ID of the user whose notification is to be deleted. Returns: - void Throws: - - std::runtime_error if no user is found with the given UserID or if no notification is found with the given NotificationID. + - std::runtime_error if no user is found with the given UserID or + if no notification is found with the given NotificationID. */ void UserManagementService::deleteNotification(const std::string& notificationID, const std::string& userID) { - auto& usersMap = m_dataStore.getUsers(); - if (usersMap.find(userID) == -1) + DataStoreLockGuard lock(m_dataStore); + auto& trackedUsersMap = m_dataStore.getUsers(); + auto& trackedNotificationsMap = m_dataStore.getNotifications(); + int userIndex = trackedUsersMap.find(userID); + if (userIndex == -1) { throw std::runtime_error("No user found with given UserID"); } - User* user = usersMap[userID]; + User* user = trackedUsersMap.getValueAt(userIndex).data; auto& notifications = user->getNotifications(); if (notifications.find(notificationID) == -1) { throw std::runtime_error("No notification found with given NotificationID"); } - notifications.remove(notificationID); -} - -/* -Function: loadUsers -Description: Loads users and notifications from persistent storage into the datastore. - Validates that each notification’s recipient exists and attaches the - notification to the corresponding user. -Parameters: - - None -Returns: - - void -Throws: - - std::runtime_error if a notification recipient user ID is invalid -*/ -void UserManagementService::loadUsers() -{ - util::FileManager userFileManager(config::file::USER_FILE); - util::FileManager notificationFileManager(config::file::NOTIFICATION_FILE); - auto& users = m_dataStore.getUsers(); - auto usersMap = userFileManager.load(); - auto notificationsMap = notificationFileManager.load(); - int numberOfUsers = usersMap.getSize(); - int numberOfNotifications = notificationsMap.getSize(); - for (int index = 0; index < numberOfUsers; index++) - { - users[usersMap.getKeyAt(index)] = usersMap.getValueAt(index); - } - for (int index = 0; index < numberOfNotifications; index++) - { - Notification* notification = notificationsMap.getValueAt(index); - const std::string& recipientUserId = notification->getRecipientUserId(); - int userIndex = users.find(recipientUserId); - if (userIndex == -1) - { - throw std::runtime_error("Invalid recipient user ID"); - } - User* user = users.getValueAt(userIndex); - user->addNotification(notification); - } -} - -/* -Function: saveUsers -Description: Saves users and their notifications from the datastore to persistent storage. - Collects notifications from all users into a single map before saving. -Parameters: - - None -Returns: - - void -*/ -void UserManagementService::saveUsers() -{ - util::FileManager userFileManager(config::file::USER_FILE); - util::FileManager notificationFileManager(config::file::NOTIFICATION_FILE); - auto& users = m_dataStore.getUsers(); - util::Map notifications; - for (int userIndex = 0; userIndex < users.getSize(); userIndex++) - { - User* user = users.getValueAt(userIndex); - auto& userNotifications = user->getNotifications(); - for (int notificationIndex = 0; notificationIndex < userNotifications.getSize(); notificationIndex++) - { - notifications[userNotifications.getKeyAt(notificationIndex)] = - userNotifications.getValueAt(notificationIndex); - } - } - userFileManager.save(users); - notificationFileManager.save(notifications); + int notificationIndex = trackedNotificationsMap.find(notificationID); + if (notificationIndex == -1) + { + throw std::runtime_error("No notification found with given NotificationID"); + } + notifications[notificationID]->setState(util::State::INACTIVE); + trackedNotificationsMap.getValueAt(notificationIndex).state = RecordState::MODIFIED; + m_dataStore.saveNotifications(); } /* @@ -270,7 +233,9 @@ Return type: util::Map */ util::Map UserManagementService::getUsers() { - return m_dataStore.getUsers(); + DataStoreLockGuard lock(m_dataStore); + auto users = util::getObjects(m_dataStore.getUsers()); + return users; } /* @@ -281,10 +246,12 @@ Return type: User* */ User* UserManagementService::getUser(const std::string& userID) { - int index = m_dataStore.getUsers().find(userID); + DataStoreLockGuard lock(m_dataStore); + auto& trackedUsersMap = m_dataStore.getUsers(); + int index = trackedUsersMap.find(userID); if (index != -1) { - return m_dataStore.getUsers().getValueAt(index); + return trackedUsersMap.getValueAt(index).data; } return nullptr; } @@ -300,35 +267,53 @@ void UserManagementService::removeUser(const std::string& userID) InventoryManagementService inventoryManagementService; PaymentManagementService paymentManagementService; ServiceManagementService serviceManagementService; - int index = m_dataStore.getUsers().find(userID); + DataStoreLockGuard lock(m_dataStore); + auto& trackedUsersMap = m_dataStore.getUsers(); + int index = trackedUsersMap.find(userID); if (index != -1) { - User* user = m_dataStore.getUsers().getValueAt(index); + User* user = trackedUsersMap.getValueAt(index).data; if (user != nullptr) { if (user->getUserType() == util::UserType::CUSTOMER) { - serviceManagementService.cancelCustomerServiceBookings(userID); + serviceManagementService.cancelCustomerServiceBookings(userID); } if (user->getUserType() == util::UserType::TECHNICIAN) { serviceManagementService.cancelTechnicianJobs(userID); } - user->setState(util::State::INACTIVE); inventoryManagementService.detach(user); paymentManagementService.detach(user); serviceManagementService.detach(user); + user->setState(util::State::INACTIVE); + trackedUsersMap.getValueAt(index).state = RecordState::MODIFIED; + m_dataStore.saveUsers(); } } } -util::Map UserManagementService::getUsers(util::UserType type) +/* +Function: getUsers +Description: Retrieves all active users of the specified type from + the DataStore. +Parameters: + - type: The user type to filter by + (ADMIN, CUSTOMER, or TECHNICIAN). +Returns: + - util::Map: + Collection of active users matching the specified type, + keyed by user ID. +*/ +util::Map UserManagementService::getUsers(util::UserType type) { - util::Map& currentUsers = m_dataStore.getUsers(); + DataStoreLockGuard lock(m_dataStore); + auto& trackedUsersMap = m_dataStore.getUsers(); + util::Map currentUsers = util::getObjects(trackedUsersMap); util::Map filteredUsersMap; - for (int iterator = 0; iterator < currentUsers.getSize(); iterator++) + for (int index = 0; index < currentUsers.getSize(); index++) { - User* currentUser = currentUsers.getValueAt(iterator); + User* currentUser = currentUsers.getValueAt(index); if (currentUser && currentUser->getState() == util::State::ACTIVE && currentUser->getUserType() == type) { filteredUsersMap.insert(currentUser->getId(), currentUser); diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.h b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.h index b448872..28aa446 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.h +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/services/UserManagementService.h @@ -31,6 +31,4 @@ public: util::Vector getUserNotifications(const std::string& userID); void deleteNotification(const std::string& notificationID, const std::string& userID); void ensureAdminExists(); - void loadUsers(); - void saveUsers(); }; diff --git a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.cpp b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.cpp index 4596d9b..926fc9e 100644 --- a/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.cpp +++ b/Trenser.VehicleServiceSystem/Trenser.VehicleServiceSystem/views/UserInterface.cpp @@ -27,8 +27,11 @@ void UserInterface::run() { try { - m_controller.loadSystemData(); - m_controller.runSystemChecks(); + if (!m_controller.initialize()) + { + std::cout << "Error: Failed to initialize the system!"; + return; + } bool isMenuActive = true; while (isMenuActive) { @@ -49,7 +52,7 @@ void UserInterface::run() util::pressEnter(); } } - m_controller.saveSystemData(); + m_controller.shutdown(); } catch (const std::invalid_argument& exception) {