From 3f69ee946c5f172f00a7b54a8ad3e8b375a08611 Mon Sep 17 00:00:00 2001
From: Harsh Mahajan This controller provides a set of endpoints for performing CRUD operations
+ * on books. The operations include retrieving a list of all books, fetching
+ * a book by its ID, adding a new book, updating an existing book, and deleting
+ * a book. All endpoints are accessible under the base URL path Note: The {@link ResourceNotFoundException} is thrown when an invalid book ID is
+ * provided for retrieval, update, or deletion. Usage examples for each endpoint can be found in the API documentation. This endpoint handles GET requests to This endpoint handles GET requests to This endpoint handles POST requests to This endpoint handles PUT requests to This endpoint handles DELETE requests to This service provides methods to perform CRUD operations on books, including
- * retrieving all books, retrieving a book by its ID, adding a new book, updating
- * an existing book, and deleting a book by its ID. This service handles various CRUD operations, such as retrieving all books, fetching
+ * a book by its ID, adding a new book, updating book details, and deleting a book from the system. Each method in this service interacts with the {@link BookRepository} to
- * perform database operations. In the case of an invalid book ID being provided, the service throws a
+ * All interactions with the database are facilitated via the {@link BookRepository}.
+ * If a book with a given ID is not found, the service throws a
* {@link ResourceNotFoundException}. Usage examples and further documentation on the book management process
+ * can be found in the associated API documentation. This method interacts with the database to fetch a complete list of
+ * all {@link Book} entities available in the library's collection. If the book with the specified ID exists, it is returned as an
+ * {@link Optional}. If the book is not found, {@code Optional.empty()} is returned. This method saves the provided {@link Book} entity to the database.
+ * The book entity must contain the necessary details such as title, author,
+ * and publication details. When called, this method updates the properties of an existing book
+ * using the new data passed in {@code bookDetails}. If the book with the
+ * specified ID does not exist, a {@link ResourceNotFoundException} is thrown. If the book with the specified ID exists, it is removed from the system.
+ * If not, a {@link ResourceNotFoundException} is thrown. This interface defines the contract for sending emails asynchronously to recipients.
+ * Implementing classes are responsible for constructing and sending the email, as well as
+ * updating the status of notifications (represented by {@link Notifications}) within the system. The email sending process involves constructing an email with a subject, body, and recipient
+ * details, and ensuring that the notification entity is updated based on whether the email
+ * was successfully sent or encountered an error. Classes implementing this interface typically use a mailing service such as
+ * {@link org.springframework.mail.javamail.JavaMailSender} to perform the actual email delivery. This method is responsible for constructing the email message, sending it to the recipient,
+ * and updating the corresponding notification status within the system based on the outcome.
+ * The email body can be in HTML or plain text format, and the associated {@link Notifications} entity
+ * tracks the status of the email (e.g., SENT or FAILED). In case of errors during the sending process, the implementation of this method should handle
+ * the exceptions and log any failures accordingly. The notification status should be updated to reflect
+ * the success or failure of the email operation. This service manages the creation and sending of MIME email messages, as well as updating the
+ * status of notifications within the system. It ensures that emails are sent in the background
+ * using asynchronous execution, allowing the main thread to remain responsive. In the case of a failed email sending operation, the service logs the error, updates
+ * the notification status to {@link NotificationStatus#FAILED}, and throws an {@link IllegalStateException}. This method creates a MIME message and sends it to the recipient using
+ * the configured {@link JavaMailSender}. If the email is successfully sent, the
+ * notification's status is updated to {@link NotificationStatus#SENT}. In case of a failure,
+ * the status is updated to {@link NotificationStatus#FAILED} and an error is logged. This method runs asynchronously, meaning the main application flow is not blocked
+ * while the email is being processed and sent. The {@code ErrorDetails} record captures essential information about errors
+ * that occur within the application, such as the time the error occurred, a message
+ * describing the error, and any additional details that may be helpful for debugging. The compiler automatically generates several members for this record, including:
- * Private final fields:
- * /api/books
./api/books
and
+ * returns a list of all books currently available in the library./api/books/{id}
+ * and returns the details of the book with the specified ID./api/books
+ * to add a new book to the library./api/books/{id}
+ * to update the details of an existing book in the library./api/books/{id}
+ * to remove a book from the library.
*
*
- * For the ErrorDetails record, the compiler will automatically generate the following members:
- *
- *
- *
- * Public constructor: - *
public ErrorDetails(Date timestamp, String message, String details) { ... }- * - *
- * Public getter methods: - *
- * toString() method: - *
public String toString() { return "ErrorDetails[timestamp=" + timestamp + ", message=" + message + ", details=" + details + "]"; }- * - *
- * equals() method: - *
@Override - * public boolean equals(Object obj) { - * if (this == obj) return true; - * if (obj == null || getClass() != obj.getClass()) return false; - * ErrorDetails other = (ErrorDetails) obj; - * return timestamp.equals(other.timestamp) && message.equals(other.message) && details.equals(other.details); - * }- * - *
- * hashCode() method: - *
@Override - * public int hashCode() { - * return java.util.Objects.hash(timestamp, message, details); - * }- * + *
The following private final fields are automatically generated:
+ *private final Date timestamp;
- The date and time when the error occurred.private final String message;
- A brief message describing the error.private final String details;
- Additional details about the error that may be useful for troubleshooting.The following public methods are automatically generated for the record:
+ *public Date timestamp() { return timestamp; }
- Returns the timestamp of the error.public String message() { return message; }
- Returns the error message.public String details() { return details; }
- Returns any additional error details.The following methods are also generated:
+ *public String toString() { return "ErrorDetails[timestamp=" + timestamp + ", message=" + message + ", details=" + details + "]"; }+ *
@Override + * public boolean equals(Object obj) { + * if (this == obj) return true; + * if (obj == null || getClass() != obj.getClass()) return false; + * ErrorDetails other = (ErrorDetails) obj; + * return timestamp.equals(other.timestamp) && message.equals(other.message) && details.equals(other.details); + * }+ *
@Override + * public int hashCode() { + * return java.util.Objects.hash(timestamp, message, details); + * }+ *
This class provides centralized exception handling for all controllers in the application. + * It intercepts specific exceptions thrown during the execution of the application and returns + * appropriate HTTP responses to the client.
+ * + *The primary purpose of this class is to ensure that the API responds with meaningful error + * messages when exceptions occur, thereby improving the client experience.
*/ @ControllerAdvice public class GlobalExceptionHandler { /** * Handles {@link ResourceNotFoundException} exceptions. - * This method is triggered when a {@code ResourceNotFoundException} is thrown in the application. - * It constructs an {@link ErrorDetails} object containing the exception details and returns - * a {@link ResponseEntity} with an HTTP status of {@code 404 Not Found}. + * + *This method is triggered when a {@code ResourceNotFoundException} is thrown in the application. + * It constructs an {@link ErrorDetails} object containing the details of the exception and returns + * a {@link ResponseEntity} with an HTTP status of {@code 404 Not Found}.
* - * @param ex the exception that was thrown. - * @param request the current web request in which the exception was thrown. + *By handling this exception globally, the API ensures that all requests resulting in + * a resource not being found will return a consistent and informative response.
+ * + * @param ex the {@code ResourceNotFoundException} that was thrown. + * @param request the current web request during which the exception occurred. * @return a {@link ResponseEntity} containing the {@link ErrorDetails} and an HTTP status of {@code 404 Not Found}. */ @ExceptionHandler(ResourceNotFoundException.class) public ResponseEntity> resourceNotFoundException(ResourceNotFoundException ex, WebRequest request) { + // Create an ErrorDetails object to hold error information ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false)); + + // Return a response entity with the error details and HTTP status return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND); } } diff --git a/src/main/java/com/libraryman_api/exception/ResourceNotFoundException.java b/src/main/java/com/libraryman_api/exception/ResourceNotFoundException.java index 56a5840..da97374 100644 --- a/src/main/java/com/libraryman_api/exception/ResourceNotFoundException.java +++ b/src/main/java/com/libraryman_api/exception/ResourceNotFoundException.java @@ -5,27 +5,30 @@ /** * Custom exception class to handle scenarios where a requested resource * is not found in the Library Management System. - * This exception is thrown when an operation fails to locate a resource such as - * a book, member, or borrowing record. + * + *This exception is thrown when an operation fails to locate a resource such as + * a book, member, or borrowing record.
+ * + *By using this exception, the application can provide meaningful feedback to clients + * when they attempt to access a resource that does not exist.
*/ public class ResourceNotFoundException extends RuntimeException { /** * The {@code serialVersionUID} is a unique identifier for each version of a serializable class. * It is used during the deserialization process to verify that the sender and receiver of a - * serialized object have loaded classes for that object that are compatible with each other. + * serialized object have loaded classes that are compatible with each other. * - * The {@code serialVersionUID} field is important for ensuring that a serialized class - * (especially when transmitted over a network or saved to disk) can be successfully deserialized, - * even if the class definition changes in later versions. If the {@code serialVersionUID} does not - * match during deserialization, an {@code InvalidClassException} is thrown. + *Including this field is important for ensuring that a serialized class can be successfully + * deserialized, even if the class definition changes in later versions. If the {@code serialVersionUID} + * does not match during deserialization, an {@code InvalidClassException} is thrown.
* - * This field is optional, but it is good practice to explicitly declare it to prevent - * automatic generation, which could lead to compatibility issues when the class structure changes. + *This field is optional, but it is good practice to explicitly declare it to prevent + * automatic generation, which could lead to compatibility issues when the class structure changes.
* - * The {@code @Serial} annotation is used here to indicate that this field is related to - * serialization. This annotation is available starting from Java 14 and helps improve clarity - * regarding the purpose of this field. + *The {@code @Serial} annotation indicates that this field is related to serialization. This + * annotation is available starting from Java 14 and helps improve clarity regarding the purpose + * of this field.
*/ @Serial private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/libraryman_api/fine/Fines.java b/src/main/java/com/libraryman_api/fine/Fines.java index 48e06c2..b52cd33 100644 --- a/src/main/java/com/libraryman_api/fine/Fines.java +++ b/src/main/java/com/libraryman_api/fine/Fines.java @@ -4,54 +4,98 @@ import java.math.BigDecimal; +/** + * Represents a fine in the Library Management System. + * + *This entity is responsible for storing information about fines incurred by library members, + * including the amount of the fine and whether it has been paid.
+ */ @Entity public class Fines { + + /** + * Unique identifier for the fine. + *This field is automatically generated using a sequence generator.
+ */ @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, - generator = "fine_id_generator") - @SequenceGenerator(name = "fine_id_generator", - sequenceName = "fine_id_sequence", - allocationSize = 1) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "fine_id_generator") + @SequenceGenerator(name = "fine_id_generator", sequenceName = "fine_id_sequence", allocationSize = 1) @Column(name = "fine_id") private int fineId; -/** - * precision = 10 means the total number of digits (including decimal places) is 10. - * scale = 2 means the number of decimal places is 2. - * @Column(nullable = false, precision = 10, scale = 2) - * */ - @Column(nullable = false, scale = 2) + /** + * The amount of the fine. + *This field has a precision of 10, allowing for a total of 10 digits, + * with 2 decimal places. It cannot be null.
+ */ + @Column(nullable = false, precision = 10, scale = 2) private BigDecimal amount; + /** + * Indicates whether the fine has been paid. + *This field is set to false by default, indicating that the fine is unpaid when created.
+ */ @Column(nullable = false) private boolean paid = false; + /** + * Default constructor for the Fines entity. + */ public Fines() { } - - public Fines( BigDecimal amount, boolean paid) { - + /** + * Constructs a new Fines object with the specified amount and payment status. + * + * @param amount the amount of the fine + * @param paid indicates whether the fine has been paid + */ + public Fines(BigDecimal amount, boolean paid) { this.amount = amount; this.paid = paid; } + /** + * Gets the amount of the fine. + * + * @return the amount of the fine + */ public BigDecimal getAmount() { return amount; } + /** + * Sets the amount of the fine. + * + * @param amount the amount to set + */ public void setAmount(BigDecimal amount) { this.amount = amount; } + /** + * Checks if the fine has been paid. + * + * @return true if the fine has been paid, false otherwise + */ public boolean isPaid() { return paid; } + /** + * Sets the payment status of the fine. + * + * @param paid indicates whether the fine has been paid + */ public void setPaid(boolean paid) { this.paid = paid; } + /** + * Gets the unique identifier of the fine. + * + * @return the fine ID + */ public int getFineId() { return fineId; } diff --git a/src/main/java/com/libraryman_api/member/MemberController.java b/src/main/java/com/libraryman_api/member/MemberController.java index 246589c..6e5880c 100644 --- a/src/main/java/com/libraryman_api/member/MemberController.java +++ b/src/main/java/com/libraryman_api/member/MemberController.java @@ -83,4 +83,4 @@ public Members updateMember(@PathVariable int id, @RequestBody Members memberDet public void deleteMember(@PathVariable int id) { memberService.deleteMember(id); } -} +} \ No newline at end of file diff --git a/src/main/java/com/libraryman_api/member/MemberService.java b/src/main/java/com/libraryman_api/member/MemberService.java index b73e384..e58105d 100644 --- a/src/main/java/com/libraryman_api/member/MemberService.java +++ b/src/main/java/com/libraryman_api/member/MemberService.java @@ -3,6 +3,7 @@ import com.libraryman_api.exception.ResourceNotFoundException; import com.libraryman_api.notification.NotificationService; import org.springframework.stereotype.Service; + import java.util.List; import java.util.Optional; @@ -52,9 +53,11 @@ public ListThis controller provides API endpoints for retrieving, creating, updating, + * and deleting library members. It interacts with {@link MemberService} to + * manage these operations and uses standard HTTP responses for success or error scenarios.
+ * + * @see MemberService */ @RestController @RequestMapping("/api/members") @@ -19,16 +24,18 @@ public class MemberController { /** * Constructs a new {@code MemberController} with the specified {@link MemberService}. * - * @param memberService the service to handle member-related operations + * @param memberService the service responsible for managing member-related operations */ public MemberController(MemberService memberService) { this.memberService = memberService; } /** - * Retrieves a list of all library members. + * Retrieves a list of all members in the library system. * - * @return a list of {@link Members} representing all members in the library + *This method handles HTTP GET requests and returns a list of all members.
+ * + * @return a list of {@link Members} representing all members in the system */ @GetMapping public ListThis method handles HTTP GET requests with a member ID as a path variable. + * If the member is not found, a {@link ResourceNotFoundException} is thrown.
* * @param id the ID of the member to retrieve - * @return a {@link ResponseEntity} containing the found {@link Members} object + * @return a {@link ResponseEntity} containing the member data if found + * @throws ResourceNotFoundException if the member with the given ID does not exist */ @GetMapping("/{id}") public ResponseEntityThis method handles HTTP POST requests to create a new member record.
* * @param member the {@link Members} object representing the new member - * @return the added {@link Members} object + * @return the newly added {@link Members} object */ @PostMapping public Members addMember(@RequestBody Members member) { @@ -61,12 +73,15 @@ public Members addMember(@RequestBody Members member) { } /** - * Updates an existing library member. - * If the member is not found, a {@link ResourceNotFoundException} is thrown. + * Updates the details of an existing member. + * + *This method handles HTTP PUT requests to update a member's details. + * If the member is not found, a {@link ResourceNotFoundException} is thrown.
* * @param id the ID of the member to update * @param memberDetails the {@link Members} object containing the updated details * @return the updated {@link Members} object + * @throws ResourceNotFoundException if the member with the given ID does not exist */ @PutMapping("/{id}") public Members updateMember(@PathVariable int id, @RequestBody Members memberDetails) { @@ -74,13 +89,16 @@ public Members updateMember(@PathVariable int id, @RequestBody Members memberDet } /** - * Deletes a library member by their ID. - * If the member is not found, a {@link ResourceNotFoundException} is thrown. + * Deletes a member by their ID. + * + *This method handles HTTP DELETE requests to remove a member from the system. + * If the member is not found, a {@link ResourceNotFoundException} is thrown.
* * @param id the ID of the member to delete + * @throws ResourceNotFoundException if the member with the given ID does not exist */ @DeleteMapping("/{id}") public void deleteMember(@PathVariable int id) { memberService.deleteMember(id); } -} \ No newline at end of file +} diff --git a/src/main/java/com/libraryman_api/member/MemberService.java b/src/main/java/com/libraryman_api/member/MemberService.java index e58105d..7d64fc6 100644 --- a/src/main/java/com/libraryman_api/member/MemberService.java +++ b/src/main/java/com/libraryman_api/member/MemberService.java @@ -3,24 +3,24 @@ import com.libraryman_api.exception.ResourceNotFoundException; import com.libraryman_api.notification.NotificationService; import org.springframework.stereotype.Service; - import java.util.List; import java.util.Optional; /** - * Service class responsible for managing member-related operations in the LibraryMan system. + * Service class responsible for handling operations related to library members, + * including retrieving, adding, updating, and deleting member records. * - *This service provides methods for retrieving, adding, updating, and deleting member records. - * It integrates with the {@link NotificationService} to send notifications related to member - * activities such as account creation, updates, and deletions.
+ *Integrates with {@link NotificationService} to manage notifications for + * various member-related actions such as account creation, updates, and deletions.
* - *Each method interacts with the {@link MemberRepository} to perform database operations, ensuring - * proper transactional behavior and consistency.
+ *Uses {@link MemberRepository} for database interactions. In cases where a + * member is not found, a {@link ResourceNotFoundException} is thrown.
* - *In cases where a member record is not found, the service throws a - * {@link ResourceNotFoundException} to indicate the error.
+ *This service ensures consistency and proper transaction management + * while interacting with the database.
* - * @author Ajay Negi + * @see MemberRepository + * @see NotificationService */ @Service public class MemberService { @@ -29,10 +29,10 @@ public class MemberService { private final NotificationService notificationService; /** - * Constructs a new {@code MemberService} with the specified repositories and services. + * Constructs a {@code MemberService} with the necessary dependencies. * - * @param memberRepository the repository for managing member records - * @param notificationService the service for sending notifications related to member activities + * @param memberRepository the repository used for managing member records + * @param notificationService the service used for sending notifications related to member activities */ public MemberService(MemberRepository memberRepository, NotificationService notificationService) { this.memberRepository = memberRepository; @@ -40,92 +40,72 @@ public MemberService(MemberRepository memberRepository, NotificationService noti } /** - * Retrieves all members from the database. + * Retrieves all members from the system. * - * @return a list of all members + * @return a list of all members present in the library database */ public ListThis method saves the new member record in the database and sends a notification - * about the account creation.
+ * Adds a new member to the system and sends an account creation notification. * - * @param member the member details to be added - * @return the saved member record + * @param member the new member to add to the system + * @return the saved member entity */ public Members addMember(Members member) { - Members savedMember = memberRepository.save(member); - notificationService.accountCreatedNotification(savedMember); - return savedMember; + Members currentMember = memberRepository.save(member); + notificationService.accountCreatedNotification(currentMember); + return currentMember; } /** - * Updates an existing member's details. - * - *This method updates the member's details in the database. It throws a - * {@link ResourceNotFoundException} if the member is not found. After updating, - * a notification about the account details update is sent.
+ * Updates an existing member's details. Throws a {@link ResourceNotFoundException} if the member + * is not found. After updating, an account details update notification is sent. * * @param memberId the ID of the member to update * @param memberDetails the updated member details - * @return the updated member record + * @return the updated member entity * @throws ResourceNotFoundException if the member is not found */ public Members updateMember(int memberId, Members memberDetails) { - Members existingMember = getMemberById(memberId); - updateMemberDetails(existingMember, memberDetails); - Members updatedMember = memberRepository.save(existingMember); - notificationService.accountDetailsUpdateNotification(updatedMember); - return updatedMember; + Members member = memberRepository.findById(memberId) + .orElseThrow(() -> new ResourceNotFoundException("Member not found")); + member.setName(memberDetails.getName()); + member.setEmail(memberDetails.getEmail()); + member.setPassword(memberDetails.getPassword()); + member.setRole(memberDetails.getRole()); + member.setMembershipDate(memberDetails.getMembershipDate()); + member = memberRepository.save(member); + notificationService.accountDetailsUpdateNotification(member); + return member; } /** - * Deletes a member from the library system. - * - *This method deletes the member record from the database after ensuring that - * the member has no outstanding fines or borrowed books. Before deletion, it - * sends a notification about the account deletion.
+ * Deletes a member from the system after ensuring no outstanding fines or borrowed books exist. + * Sends an account deletion notification before deletion. * * @param memberId the ID of the member to delete * @throws ResourceNotFoundException if the member is not found */ public void deleteMember(int memberId) { - Members member = getMemberById(memberId); + Members member = memberRepository.findById(memberId) + .orElseThrow(() -> new ResourceNotFoundException("Member not found")); // TODO: Implement logic to check if the member has any outstanding fines or borrowed books. - // If there are no pending obligations, delete all related notifications, borrowings, and fines. notificationService.accountDeletionNotification(member); memberRepository.delete(member); } - - /** - * Updates the details of an existing member. - * - * @param existingMember the member to update - * @param newDetails the new member details to apply - */ - private void updateMemberDetails(Members existingMember, Members newDetails) { - existingMember.setName(newDetails.getName()); - existingMember.setEmail(newDetails.getEmail()); - existingMember.setPassword(newDetails.getPassword()); - existingMember.setRole(newDetails.getRole()); - existingMember.setMembershipDate(newDetails.getMembershipDate()); - } }