diff --git a/src/main/java/edu/group5/app/model/DBRepository.java b/src/main/java/edu/group5/app/model/DBRepository.java
index f3363b7..3cd1fa9 100644
--- a/src/main/java/edu/group5/app/model/DBRepository.java
+++ b/src/main/java/edu/group5/app/model/DBRepository.java
@@ -1,18 +1,21 @@
package edu.group5.app.model;
+
import java.util.HashMap;
import java.util.Map;
import java.util.List;
+
/**
* Abstract base class for repositories that store their data
* in a database-related structure.
*
*
- * Extends {@link Repository} and specifies that the content
- * is stored as a {@link Map}.
+ * Extends {@link Repository} and specifies that the content
+ * is stored as a {@link Map}.
*
*/
public abstract class DBRepository extends Repository {
protected final Map contentLock;
+
/**
* Constructs a DBRepository with the given content.
*
@@ -23,19 +26,18 @@ protected DBRepository(Map content) {
this.contentLock = new HashMap<>();
}
- protected void updateContentLock() {
- synchronized (contentLock) {
- contentLock.clear();
- contentLock.putAll(this.content);
- }
- }
+ protected abstract void updateContentLock();
public abstract boolean addContent(V value);
/**
- * Exports the repository content as a list of Object arrays, where each array represents a row of data.
- * This method is intended for converting the repository content into a format suitable for database storage or export.
- * @return a List of Object arrays representing the repository content for database export
+ * Exports the repository content as a list of Object arrays, where each array
+ * represents a row of data.
+ * This method is intended for converting the repository content into a format
+ * suitable for database storage or export.
+ *
+ * @return a List of Object arrays representing the repository content for
+ * database export
*/
public abstract List export();
}
diff --git a/src/main/java/edu/group5/app/model/donation/DonationRepository.java b/src/main/java/edu/group5/app/model/donation/DonationRepository.java
index 6181460..a55ea74 100644
--- a/src/main/java/edu/group5/app/model/donation/DonationRepository.java
+++ b/src/main/java/edu/group5/app/model/donation/DonationRepository.java
@@ -15,7 +15,7 @@
* Repository class for Donation.
*
*
- * Extends {@link DBRepository} and manages Donation entities.
+ * Extends {@link DBRepository} and manages Donation entities.
*
*/
public class DonationRepository extends DBRepository {
@@ -23,10 +23,12 @@ public class DonationRepository extends DBRepository {
/**
* Constructs DonationRepository from a list of Object[] rows from the database.
- * @param rows List of Object[] representing donations from the DB.
- * Each row must have 6 elements:
- * [donationId, userId, organizationId, amount, date, paymentMethod]
- * @throws IllegalArgumentException if the input list is null or any row is invalid
+ *
+ * @param rows List of Object[] representing donations from the DB.
+ * Each row must have 6 elements:
+ * [donationId, userId, organizationId, amount, date, paymentMethod]
+ * @throws IllegalArgumentException if the input list is null or any row is
+ * invalid
*/
public DonationRepository(List rows) {
super(new HashMap<>());
@@ -35,12 +37,12 @@ public DonationRepository(List rows) {
}
this.content = new HashMap<>();
for (Object[] row : rows) {
- if (row == null || row.length != 6 ) {
+ if (row == null || row.length != 6) {
throw new IllegalArgumentException("Each row must contain exactly 6 elements");
}
int donationId = (int) row[0];
int customerId = (int) row[1];
- int organizationId = (int) row[2];
+ int organizationId = (int) row[2];
BigDecimal amount = (BigDecimal) row[3];
Timestamp date = (Timestamp) row[4];
String paymentMethod = (String) row[5];
@@ -48,23 +50,39 @@ public DonationRepository(List rows) {
Donation donation = new Donation(donationId, customerId, organizationId, amount, date, paymentMethod);
this.content.put(donationId, donation);
}
- super.updateContentLock();
+ this.updateContentLock();
+ }
+
+ @Override
+ protected void updateContentLock() {
+ synchronized (contentLock) {
+ this.contentLock.clear();
+ this.contentLock.putAll(this.content);
+ }
}
@Override
public List export() {
- return content.entrySet().stream()
- .sorted(Map.Entry.comparingByKey())
- .map(entry -> { Donation donation = entry.getValue();
- return new Object[] {
- donation.donationId(), donation.userId(),
- donation.organizationId(), donation.amount(),
- donation.date(), donation.paymentMethod()};})
- .toList();
+ Map output = new HashMap<>(this.content);
+ for (int i : super.contentLock.keySet()) {
+ output.remove(i);
+ }
+ this.updateContentLock();
+ return output.entrySet().stream()
+ .sorted(Map.Entry.comparingByKey())
+ .map(entry -> {
+ Donation donation = entry.getValue();
+ return new Object[] {
+ donation.donationId(), donation.userId(),
+ donation.organizationId(), donation.amount(),
+ donation.date(), donation.paymentMethod() };
+ })
+ .toList();
}
/**
* Retrieves a donation by its ID.
+ *
* @param donationId the ID of the donation to retrieve
* @return the Donation object with the specified ID, or null if not found
* @throws IllegalArgumentException if the donationId is not positive
@@ -77,10 +95,12 @@ public Donation getDonationById(int donationId) {
}
/**
- * Generates the next donation ID based on the current maximum ID in the repository.
+ * Generates the next donation ID based on the current maximum ID in the
+ * repository.
+ *
* @return the next donation ID to be used for a new donation
*/
- public int getNextDonationId() {
+ public int getNextDonationId() {
return content.keySet().stream().max(Integer::compareTo).orElse(0) + 1;
} /* TODO change this when data database is introduced */
@@ -91,22 +111,22 @@ public Map getAllDonations() {
/**
* Adds a new donation to the repository
*
- * The donation is stored using its {@code donationId} as the key.
- * If a donation with the same ID already exists, the donation
- * will not be added.
+ * The donation is stored using its {@code donationId} as the key.
+ * If a donation with the same ID already exists, the donation
+ * will not be added.
*
*
* @param donation the donation to add
* @return {@code true} if the donation was successfully added, and
- * {@code false} if a donation with the same ID already exists
+ * {@code false} if a donation with the same ID already exists
*/
@Override
public boolean addContent(Donation donation) {
if (donation == null) {
throw new IllegalArgumentException("Donation cannot be null");
}
- if (content.containsKey(donation.donationId())){
- return false;
+ if (content.containsKey(donation.donationId())) {
+ return false;
}
this.content.put(donation.donationId(), donation);
return true;
@@ -116,12 +136,12 @@ public boolean addContent(Donation donation) {
* Returns all donations sorted by date (ascending).
*
*
- * The returned map preserves the sorted order.
+ * The returned map preserves the sorted order.
*
*
* @return a new {@link HashMap} containing the donations sorted by date
*/
- public HashMap sortByDate(){
+ public HashMap sortByDate() {
return content.entrySet().stream()
.sorted(Map.Entry.comparingByValue(
Comparator.comparing(Donation::date)))
@@ -136,7 +156,7 @@ public HashMap sortByDate(){
* Returns all donations sorted by amount (ascending).
*
*
- * The returned map preserves the sorted order from lowest to highest amount.
+ * The returned map preserves the sorted order from lowest to highest amount.
*
*
* @return a new {@link HashMap} containing the donations sorted by amount.
@@ -149,12 +169,12 @@ public HashMap sortByAmount() {
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
- LinkedHashMap::new
- ));
+ LinkedHashMap::new));
}
/**
* Returns all donations associated with a specific organization.
+ *
* @param orgNumber the organization ID to filter by
* @return a map containing all donations that belong to the given organization
* @throws IllegalArgumentException if the orgNumber is not positive
@@ -165,17 +185,17 @@ public HashMap filterByOrganization(int orgNumber) {
}
return content.entrySet()
.stream()
- .filter(entry -> entry.getValue().organizationId() == orgNumber)
+ .filter(entry -> entry.getValue().organizationId() == orgNumber)
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
- LinkedHashMap::new
- ));
+ LinkedHashMap::new));
}
/**
* Returns all donations made by a specific user.
+ *
* @param userId the user ID to filter by
* @return a map containing all donations that belong to the given user
* @throws IllegalArgumentException if the userId is not positive
@@ -190,7 +210,6 @@ public HashMap filterByUser(int userId) {
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
- LinkedHashMap::new
- ));
+ LinkedHashMap::new));
}
}
diff --git a/src/main/java/edu/group5/app/model/user/UserRepository.java b/src/main/java/edu/group5/app/model/user/UserRepository.java
index 692126f..193f433 100644
--- a/src/main/java/edu/group5/app/model/user/UserRepository.java
+++ b/src/main/java/edu/group5/app/model/user/UserRepository.java
@@ -6,11 +6,13 @@
import edu.group5.app.model.DBRepository;
-public class UserRepository extends DBRepository{
+public class UserRepository extends DBRepository {
public final static String ROLE_CUSTOMER = "Customer";
+
/**
* Constructs UserRepository using Hashmap,
* and extends the content from DBRepository.
+ *
* @param content the underlying map used to store users,
* where the key represents the user ID
*/
@@ -20,7 +22,7 @@ public UserRepository(List rows) {
throw new IllegalArgumentException("The list of rows cannot be null");
}
for (Object[] row : rows) {
- if (row == null || row.length != 6 ) {
+ if (row == null || row.length != 6) {
throw new IllegalArgumentException("Each row must contain exactly 6 elements");
}
int userId = (int) row[0];
@@ -38,28 +40,46 @@ public UserRepository(List rows) {
}
this.content.put(userId, user);
}
- super.updateContentLock();
+ this.updateContentLock();
}
+ @Override
+ protected void updateContentLock() {
+ synchronized (contentLock) {
+ this.contentLock.clear();
+ this.contentLock.putAll(this.content);
+ }
+ }
@Override
public List export() {
- return content.entrySet().stream()
- .sorted(Map.Entry.comparingByKey())
- .map(entry -> { User user = entry.getValue();
- return new Object[]{user.getUserId(), user.getRole(),
- user.getFirstName(), user.getLastName(),
- user.getEmail(), user.getPasswordHash()};})
+ Map output = new HashMap<>(this.content);
+ for (int i : contentLock.keySet()) {
+ output.remove(i);
+ }
+ this.updateContentLock();
+ return output.entrySet().stream()
+ .sorted(Map.Entry.comparingByKey())
+ .map(entry -> {
+ User user = entry.getValue();
+ return new Object[] { user.getUserId(), user.getRole(),
+ user.getFirstName(), user.getLastName(),
+ user.getEmail(), user.getPasswordHash() };
+ })
.toList();
+
}
public HashMap getUsers() {
return new HashMap<>(content);
}
+
/**
* Retrieves a user by their unique identifier.
+ *
* @param userId the unique identifier of the user to retrieve
- * @return the user with the specified ID, or {@code null} if no such user exists
+ * @return the user with the specified ID, or {@code null} if no such user
+ * exists
* @throws IllegalArgumentException if the userId is not positive
*/
public User getUserById(int userId) {
@@ -72,12 +92,13 @@ public User getUserById(int userId) {
/**
* Generates the next user ID based on repository size.
* Uses size+1 and then moves forward if that ID is already taken.
+ *
* @return the next available user ID
* @throws IllegalStateException if no available user ID can be found
*/
- public int getNextUserId() {
+ public int getNextUserId() {
if (content.isEmpty()) {
- return 1;
+ return 1;
}
int maxKey = content.keySet().stream().max(Integer::compareTo).orElseThrow(
() -> new IllegalStateException("No keys found"));
@@ -88,21 +109,21 @@ public int getNextUserId() {
/**
* Adds a new user to the repository
*
- * The user is stored using its {@code userId} as the key.
- * If a user with the same ID already exists, the user
- * will not be added.
+ * The user is stored using its {@code userId} as the key.
+ * If a user with the same ID already exists, the user
+ * will not be added.
*
*
* @param user the user to add
* @return {@code true} if the user was successfully added, and
- * {@code false} if a user with the same ID already exists
+ * {@code false} if a user with the same ID already exists
*/
@Override
public boolean addContent(User user) {
if (user == null) {
throw new IllegalArgumentException("User cannot be null");
}
- if (content.containsKey(user.getUserId())){
+ if (content.containsKey(user.getUserId())) {
return false;
}
this.content.put(user.getUserId(), user);
@@ -111,8 +132,10 @@ public boolean addContent(User user) {
/**
* Finds a user by their email address.
+ *
* @param email the email address of the user to find
- * @return the user with the specified email address, or {@code null} if no such user exists
+ * @return the user with the specified email address, or {@code null} if no such
+ * user exists
*/
public User findUserByEmail(String email) {
if (email == null || email.trim().isEmpty()) {
@@ -122,5 +145,5 @@ public User findUserByEmail(String email) {
.filter(user -> user.getEmail().equals(email))
.findFirst()
.orElse(null);
- }
+ }
}
diff --git a/src/test/java/edu/group5/app/model/donation/DonationRepositoryTest.java b/src/test/java/edu/group5/app/model/donation/DonationRepositoryTest.java
index bdf0110..ce81b2a 100644
--- a/src/test/java/edu/group5/app/model/donation/DonationRepositoryTest.java
+++ b/src/test/java/edu/group5/app/model/donation/DonationRepositoryTest.java
@@ -263,4 +263,13 @@ void filterByUserIdThrowsIfNegative() {
() -> repo.filterByUser(0));
assertEquals("User ID must be positive", ex.getMessage());
}
+
+ @Test
+ void exportExportsOnlyNewInformation() {
+ repo.addContent(donation1);
+ repo.addContent(donation2);
+ assertEquals(2, repo.export().size());
+ repo.addContent(donation3);
+ assertEquals(1, repo.export().size());
+ }
}
\ No newline at end of file
diff --git a/src/test/java/edu/group5/app/model/user/UserRepositoryTest.java b/src/test/java/edu/group5/app/model/user/UserRepositoryTest.java
index 0700828..a4afbc8 100644
--- a/src/test/java/edu/group5/app/model/user/UserRepositoryTest.java
+++ b/src/test/java/edu/group5/app/model/user/UserRepositoryTest.java
@@ -12,6 +12,7 @@ public class UserRepositoryTest {
private UserRepository repo;
private List rows;
+private User additionalUser;
@BeforeEach
void setUp() {
@@ -19,6 +20,7 @@ void setUp() {
rows.add(new Object[]{1, "Customer", "John", "Cena", "john@example.com", "hashedpass"});
rows.add(new Object[]{2, "Customer", "Jane", "Doe", "jane@example.com", "hashedpass"});
repo = new UserRepository(rows);
+ this.additionalUser = new Customer(3, "John", "Doe", "john@example.com", "hashedpass");
}
@Test
@@ -145,4 +147,11 @@ void exportContainsAllUsers() {
assertEquals(2, exported.get(1)[0]);
assertEquals("Customer", exported.get(0)[1]);
}
+
+ @Test
+ void exportExportsOnlyNewInformation() {
+ assertEquals(0, repo.export().size());
+ repo.addContent(this.additionalUser);
+ assertEquals(1, repo.export().size());
+ }
}
\ No newline at end of file