diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..3b41682a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1d249e99 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ +application.properties + diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..d58dfb70 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip diff --git a/Instructions.md b/Instructions.md new file mode 100644 index 00000000..df676c12 --- /dev/null +++ b/Instructions.md @@ -0,0 +1,188 @@ +![logo_ironhack_blue 7](https://user-images.githubusercontent.com/23629340/40541063-a07a0a8a-601a-11e8-91b5-2f13e4e6b441.png) + +# HW | Java IronLibrary (Unit 3 homework) + +## Introduction + +For this homework, you will be building a Library Management System, that will help managing and acquiring data about the books that are being used by students. + +## Instructions + +Let's walk through the details of the homework: + +### Classes + +Four main classes are necessary to complete this homework. + +These classes will be called **Author**, **Book**, **Student** and **Issue**. + +
+ +**Book class** + +This class will have: + +- Variable called `isbn` of data type `string`, representing the **International Standard Book Number** and acting as the unique identifier for the table book (Private member) +- Variable called `title` of data type `string` (Private member) +- Variable called `category` of data type `string` (Private member) +- Variable called `quantity` of data type `integer` (Private member) +- A parameterized constructor that takes `isbn`, `title`, `category` and a `quantity` +- Public Getter functions to access these variables +- Public Setter functions to change these variables +- Optional attributes are accepted if needed based on the code structure + +
+ +**Author class** + +This class will have: + +- Variable called `authorId` of data type `integer`, auto-incremented (Private member) +- Variable called `name` of data type `string` (Private member) +- Variable called `email` of data type `string` (Private member) +- Variable called `authorBook` of data type `Book`, representing a One-to-One relationship with `Book` (Private member) +- A parameterized constructor that takes `name`, `email` and `authorBook` +- Public Getter functions to access these variables +- Public Setter functions to change these variables +- Optional attributes are accepted if needed based on the code structure + +
+ +**Issue class** + +This class will have: + +- Variable called `issueId` of data type `integer`, auto-incremented (Private member) +- Variable called `issueDate` of data type `string` (Private member) +- Variable called `returnDate` of data type `string` (Private member) +- Variable called `issueStudent` of data type `Student`, representing a One-to-One relationship with `Student`(Private member) +- Variable called `issueBook` of data type `Book`, representing a One-to-One relationship with `Book` (Private member) +- A parameterized constructor that takes `issueDate`, `returnDate`, `issueStudent` and `issueBook` +- Public Getter functions to access these variables +- Public Setter functions to change these variables +- Optional attributes are accepted if needed based on the code structure + +
+ +**Student class** + +This class will have: + +- Variable called `usn` of data type `string`, representing the **Universal Student Number** and acting as the unique identifier for the table student (Private member) +- Variable called `name` of data type `string` (Private member) +- A parameterized constructor that takes `usn` and `name` +- Public Getter functions to access these variables +- Public Setter functions to change these variables +- Optional attributes are accepted if needed based on the code structure + +## How the application works + +After starting this application, a list of options will pop up for the user. The user will be asked to input a number based on the list of options displayed, such as adding a book, searching for a book, issuing a book for a student, etc. +After a certain action is executed, the menu is re-displayed for the user automatically. + +The menu should have the following options: + +1. Add a book +2. Search book by title +3. Search book by category +4. Search book by Author +5. List all books along with author +6. Issue book to student +7. List books by usn +8. Exit + +## Actions + +1. **Add a book**: This action is responsible of adding a book and its author in the system. The user will be prompted to enter the details of both the book and the author in the following format: + +``` +Enter your choice: 1 +Enter isbn : 978-3-16-148410-0 +Enter title : The Notebook +Enter category : Romance +Enter Author name : Nicholas Sparks +Enter Author mail : nicholassparks@gmail.com +Enter number of books : 4 +``` + +2. **Search book by title**: This action is responsible for searching a book by title. + +``` +Enter your choice: 2 +Enter title : The Notebook + +Book ISBN Book Title Category No of Books +978-3-16-148410-0 The Notebook Romance 4 +``` + +3. **Search book by category**: This action is responsible for searching a book by category. + +``` +Enter your choice: 3 +Enter category : Romance + +Book ISBN Book Title Category No of Books +978-3-16-148410-0 The Notebook Romance 4 +``` + +4. **Search book by author**: This action is responsible for searching a book by author name. + +``` +Enter your choice: 4 +Enter name : Nicholas Sparks + +Book ISBN Book Title Category No of Books +978-3-16-148410-0 The Notebook Romance 4 +``` + +5. **List all books along with author**: This action is responsible for listing all the books available and there corresponding authors. + +``` +Enter your choice: 5 + +Book ISBN Book Title Category No of Books Author name Author mail +978-3-16-148410-0 The Notebook Romance 4 Nicholas Sparks nicholassparks@gmail.com +978-3-17-148410-0 Da Vinci Code Mystery 5 Dan Brown danbrown@gmail.com +``` + +6. **Issue book to student**: This action is responsible for creating a student and issuing him/her the specified book. The date issued represent the current date and the return date should be after 7 days. + +``` +Enter your choice: 6 +Enter usn : 09003688800 +Enter name : John Doe +Enter book ISBN : 978-3-17-148410-0 + +Book issued. Return date : Mon Aug 01 19:45:40 EEST 2022 +``` + +7. **List books by usn**: This action is responsible for listing all books rented by the specified student. + +``` +Enter your choice: 7 +Enter usn : 09003688800 + +Book Title Student Name Return date +Da Vinci Code John Doe 2022-08-01 16:45:40.636000 +``` + +## Requirements + +For this project, you must accomplish all of the following: + +1. Navigate through a text-based menu using Standard Input and Output. +2. Create unit tests for every method other than basic getters, setters and constructors (getters and setters with logic do require unit tests). +3. Handle all exceptions gracefully (incorrect input should not crash the program). +4. All data should be stored in a normalized SQL database. + +### Bonus + +1. Add more options that can help display more information such as **List books to be returned today**, etc. + +## Important Notes + +- Everyone in the squad should contribute equally to the project in time and lines of code written. +- All code must be reviewed before it is merged into the `master` branch. +- All squad members must participate in code review. +- Every repository should have a README file with clear instructions, demo files, or any documentation needed so other teams don't have problems with the review. +- This is intended to be a challenging assignment. You will have to rely heavily on your teammates and independent research. Learning independently is a hallmark of a good developer and our job is to turn you into good developers. This process may be frustrating but you will learn a ton! diff --git a/README.md b/README.md index df676c12..6dba3d52 100644 --- a/README.md +++ b/README.md @@ -1,101 +1,61 @@ -![logo_ironhack_blue 7](https://user-images.githubusercontent.com/23629340/40541063-a07a0a8a-601a-11e8-91b5-2f13e4e6b441.png) +# IronLibrary -# HW | Java IronLibrary (Unit 3 homework) +## Introducción -## Introduction +Este proyecto consiste en un sistema de gestión de biblioteca que permite administrar y obtener datos sobre los libros utilizados por los estudiantes. A continuación, se detallan las instrucciones para ejecutar y probar la aplicación. -For this homework, you will be building a Library Management System, that will help managing and acquiring data about the books that are being used by students. +--- -## Instructions +## Requisitos previos -Let's walk through the details of the homework: +1. **Java**: Java 21. +2. **Maven**: correctamente configurado. +3. **Base de datos**: MySQL o MariaDB (ajustando las credenciales en el archivo `application.properties`). -### Classes +--- -Four main classes are necessary to complete this homework. +## Instalación -These classes will be called **Author**, **Book**, **Student** and **Issue**. +1. Clona el repositorio: + ```bash + git clone https://github.com/VAlexS/homework-java-ironlibrary + cd homework-java-ironlibrary + ``` -
+2. Compila el proyecto: + ```bash + mvn clean install + ``` -**Book class** +3. Ejecuta la aplicación: + ```bash + mvn spring-boot:run + ``` -This class will have: +--- -- Variable called `isbn` of data type `string`, representing the **International Standard Book Number** and acting as the unique identifier for the table book (Private member) -- Variable called `title` of data type `string` (Private member) -- Variable called `category` of data type `string` (Private member) -- Variable called `quantity` of data type `integer` (Private member) -- A parameterized constructor that takes `isbn`, `title`, `category` and a `quantity` -- Public Getter functions to access these variables -- Public Setter functions to change these variables -- Optional attributes are accepted if needed based on the code structure +## Uso -
+Al iniciar la aplicación, se mostrará un menú interactivo en la consola. A continuación, se presentan capturas de pantalla y ejemplos de uso. -**Author class** +### Menú principal -This class will have: - -- Variable called `authorId` of data type `integer`, auto-incremented (Private member) -- Variable called `name` of data type `string` (Private member) -- Variable called `email` of data type `string` (Private member) -- Variable called `authorBook` of data type `Book`, representing a One-to-One relationship with `Book` (Private member) -- A parameterized constructor that takes `name`, `email` and `authorBook` -- Public Getter functions to access these variables -- Public Setter functions to change these variables -- Optional attributes are accepted if needed based on the code structure - -
- -**Issue class** - -This class will have: - -- Variable called `issueId` of data type `integer`, auto-incremented (Private member) -- Variable called `issueDate` of data type `string` (Private member) -- Variable called `returnDate` of data type `string` (Private member) -- Variable called `issueStudent` of data type `Student`, representing a One-to-One relationship with `Student`(Private member) -- Variable called `issueBook` of data type `Book`, representing a One-to-One relationship with `Book` (Private member) -- A parameterized constructor that takes `issueDate`, `returnDate`, `issueStudent` and `issueBook` -- Public Getter functions to access these variables -- Public Setter functions to change these variables -- Optional attributes are accepted if needed based on the code structure - -
- -**Student class** - -This class will have: - -- Variable called `usn` of data type `string`, representing the **Universal Student Number** and acting as the unique identifier for the table student (Private member) -- Variable called `name` of data type `string` (Private member) -- A parameterized constructor that takes `usn` and `name` -- Public Getter functions to access these variables -- Public Setter functions to change these variables -- Optional attributes are accepted if needed based on the code structure - -## How the application works - -After starting this application, a list of options will pop up for the user. The user will be asked to input a number based on the list of options displayed, such as adding a book, searching for a book, issuing a book for a student, etc. -After a certain action is executed, the menu is re-displayed for the user automatically. - -The menu should have the following options: - -1. Add a book -2. Search book by title -3. Search book by category -4. Search book by Author -5. List all books along with author -6. Issue book to student -7. List books by usn -8. Exit - -## Actions +```plaintext +=========== 📖 Iron Library =========== +1. 📕 Add a book +2. 🔎 Search book by title +3. 🗂️ Search book by category +4. 🖋️ Search book by author +5. 📚 List all books along with author +6. 🎓 Issue book to student +7. 🆔 List books by USN +8. 🚪 Exit +Choose an option: +``` -1. **Add a book**: This action is responsible of adding a book and its author in the system. The user will be prompted to enter the details of both the book and the author in the following format: +### Ejemplo: Agregar un libro -``` +```plaintext Enter your choice: 1 Enter isbn : 978-3-16-148410-0 Enter title : The Notebook @@ -103,11 +63,12 @@ Enter category : Romance Enter Author name : Nicholas Sparks Enter Author mail : nicholassparks@gmail.com Enter number of books : 4 +Record created successfully! ``` -2. **Search book by title**: This action is responsible for searching a book by title. +### Ejemplo: Buscar un libro por título -``` +```plaintext Enter your choice: 2 Enter title : The Notebook @@ -115,74 +76,25 @@ Book ISBN Book Title Category No of Books 978-3-16-148410-0 The Notebook Romance 4 ``` -3. **Search book by category**: This action is responsible for searching a book by category. - -``` -Enter your choice: 3 -Enter category : Romance - -Book ISBN Book Title Category No of Books -978-3-16-148410-0 The Notebook Romance 4 -``` - -4. **Search book by author**: This action is responsible for searching a book by author name. - -``` -Enter your choice: 4 -Enter name : Nicholas Sparks - -Book ISBN Book Title Category No of Books -978-3-16-148410-0 The Notebook Romance 4 -``` - -5. **List all books along with author**: This action is responsible for listing all the books available and there corresponding authors. +### Ejemplo: Emitir un libro a un estudiante -``` -Enter your choice: 5 - -Book ISBN Book Title Category No of Books Author name Author mail -978-3-16-148410-0 The Notebook Romance 4 Nicholas Sparks nicholassparks@gmail.com -978-3-17-148410-0 Da Vinci Code Mystery 5 Dan Brown danbrown@gmail.com -``` - -6. **Issue book to student**: This action is responsible for creating a student and issuing him/her the specified book. The date issued represent the current date and the return date should be after 7 days. - -``` +```plaintext Enter your choice: 6 Enter usn : 09003688800 Enter name : John Doe Enter book ISBN : 978-3-17-148410-0 -Book issued. Return date : Mon Aug 01 19:45:40 EEST 2022 +Book issued. Return date : 2023-10-15 ``` -7. **List books by usn**: This action is responsible for listing all books rented by the specified student. +--- -``` -Enter your choice: 7 -Enter usn : 09003688800 +## Pruebas -Book Title Student Name Return date -Da Vinci Code John Doe 2022-08-01 16:45:40.636000 -``` +El proyecto incluye pruebas unitarias para todos los servicios principales. Para ejecutarlas, utiliza el siguiente comando: -## Requirements - -For this project, you must accomplish all of the following: - -1. Navigate through a text-based menu using Standard Input and Output. -2. Create unit tests for every method other than basic getters, setters and constructors (getters and setters with logic do require unit tests). -3. Handle all exceptions gracefully (incorrect input should not crash the program). -4. All data should be stored in a normalized SQL database. - -### Bonus - -1. Add more options that can help display more information such as **List books to be returned today**, etc. +```bash +mvn test +``` -## Important Notes -- Everyone in the squad should contribute equally to the project in time and lines of code written. -- All code must be reviewed before it is merged into the `master` branch. -- All squad members must participate in code review. -- Every repository should have a README file with clear instructions, demo files, or any documentation needed so other teams don't have problems with the review. -- This is intended to be a challenging assignment. You will have to rely heavily on your teammates and independent research. Learning independently is a hallmark of a good developer and our job is to turn you into good developers. This process may be frustrating but you will learn a ton! diff --git a/mvnw b/mvnw new file mode 100644 index 00000000..19529ddf --- /dev/null +++ b/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 00000000..249bdf38 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,149 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' +$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" +if ($env:MAVEN_USER_HOME) { + $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" +} +$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..4e3c38af --- /dev/null +++ b/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.4 + + + com.example + ironlibrary + 0.0.1-SNAPSHOT + ironlibrary + Library Management System + + + + + + + + + + + + + + + 21 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + + com.mysql + mysql-connector-j + runtime + + + org.springframework.boot + spring-boot-starter-test + test + + + org.mariadb.jdbc + mariadb-java-client + 3.3.1 + + + org.junit.jupiter + junit-jupiter + 5.11.4 + test + + + org.junit.platform + junit-platform-launcher + 1.11.4 + test + + + org.mockito + mockito-junit-jupiter + 5.5.0 + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + \ No newline at end of file diff --git a/src/main/java/com/example/homework_library/HomeworkLibraryApplication.java b/src/main/java/com/example/homework_library/HomeworkLibraryApplication.java new file mode 100644 index 00000000..d7659b88 --- /dev/null +++ b/src/main/java/com/example/homework_library/HomeworkLibraryApplication.java @@ -0,0 +1,223 @@ +package com.example.homework_library; + +import com.example.homework_library.models.Author; +import com.example.homework_library.models.Book; +import com.example.homework_library.models.Issue; +import com.example.homework_library.models.Student; +import com.example.homework_library.services.AuthorService; +import com.example.homework_library.services.BookService; +import com.example.homework_library.services.IssueService; +import com.example.homework_library.services.StudentService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; + +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Scanner; + +@SpringBootApplication +public class HomeworkLibraryApplication { + + @Autowired + private BookService bookService; + + @Autowired + private StudentService studentService; + + @Autowired + private IssueService issueService; + + @Autowired + private AuthorService authorService; + + public static final String RESET = "\u001B[0m"; + public static final String GREEN = "\u001B[32m"; + public static final String CYAN = "\u001B[36m"; + public static final String RED = "\u001B[31m"; + + private final Scanner scanner = new Scanner(System.in); + + public void runMenu() { + boolean running = true; + + while (running) { + try { + menuDisplay(); + String option = scanner.nextLine().trim(); + + switch (option) { + case "1" -> addBook(); + case "2" -> searchBook(); + case "3" -> searchBookByCategory(); + case "4" -> findBookByAuthor(); + case "5" -> listAllBooks(); + case "6" -> issueBook(); + case "7" -> listAllBooksByUSN(); + case "8" -> listAllStudents(); + case "9" -> listAllAuthors(); + case "0", "exit" -> running = false; + default -> System.out.println("Invalid option. Please try again."); + } + } catch (IllegalArgumentException e) { + System.out.println("Incorrect argument: " + e.getMessage()); + } catch (NoSuchElementException e) { + System.out.println("Element not found: " + e.getMessage()); + } catch (Exception e) { + System.out.println("An unexpected error occurred: " + e.getMessage()); + } + } + + scanner.close(); + } + + private void menuDisplay() { + System.out.println(GREEN + "\n=========== 📖 Iron Library ===========" + RESET); + System.out.println(CYAN + "1. 📕 Add a book" + RESET); + System.out.println(CYAN + "2. 🔎 Search book by title" + RESET); + System.out.println(CYAN + "3. 🗂️ Search book by category" + RESET); + System.out.println(CYAN + "4. 🖋️ Search book by author" + RESET); + System.out.println(CYAN + "5. 📚 List all books along with author" + RESET); + System.out.println(CYAN + "6. 🎓 Issue book to student" + RESET); + System.out.println(CYAN + "7. 🆔 List books by USN" + RESET); + System.out.println(CYAN + "8. 👩‍🎓 List all students" + RESET); + System.out.println(CYAN + "9. ✍️ List all authors" + RESET); + System.out.println(GREEN + "-----------------------------------------" + RESET); + System.out.println(RED + "0. 🚪 Exit" + RESET); + System.out.println(GREEN + "=========================================" + RESET); + System.out.print("Choose an option: "); + } + + private void addBook() { + String isbn = prompt("Enter the ISBN: "); + String title = prompt("Enter the title of the book: "); + String category = prompt("Enter the category of the book: "); + String authorName = prompt("Enter the author of the book: "); + String mail = prompt("Enter the mail of the author: "); + int booksNumber = Integer.parseInt(prompt("Enter the number of books: ")); + + bookService.addBook(isbn, title, category, authorName, mail, booksNumber); + System.out.println("Record created successfully!"); + } + + private void searchBook() { + String title = prompt("Enter the title of the book: "); + Book book = bookService.searchBookByTitle(title); + if (book != null) { + System.out.println("Book found: " + book); + } else { + System.out.println("Book not found."); + } + } + + private void searchBookByCategory() { + String category = prompt("Enter the category of the book: "); + List books = bookService.searchBooksByCategory(category); + if (!books.isEmpty()) { + System.out.println("Books found in category " + category + ":"); + books.forEach(System.out::println); + } else { + System.out.println("Book category not found."); + } + } + + private void findBookByAuthor() { + String authorName = prompt("Enter the author of the book: "); + Book book = bookService.findBookByAuthor(authorName); + if (book != null) { + System.out.println("Book found: " + book); + } else { + System.out.println("Book not found."); + } + } + + private void listAllBooks() { + List books = bookService.listAllBooks(); + + String separator = String.format("%-90s", "").replace(' ', '='); + + System.out.println(separator); + System.out.printf("%-25s %-30s %-20s %-10s%n", + "Book ISBN", "Book Title", "Category", "Quantity"); + System.out.println(separator); + + for (Book book : books) { + System.out.printf("%-25s %-30s %-20s %-10d%n", + book.getIsbn(), book.getTitle(), book.getCategory(), book.getQuantity()); + } + + System.out.println(separator); + } + + private void listAllStudents() { + List students = studentService.listAllStudents(); + + String separator = String.format("%-50s", "").replace(' ', '='); + + System.out.println(separator); + System.out.printf("%-20s %-30s%n", "USN", "Student Name"); + System.out.println(separator); + + for (Student student : students) { + System.out.printf("%-20s %-30s%n", student.getUsn(), student.getName()); + } + + System.out.println(separator); + } + + private void listAllAuthors() { + List authors = authorService.findAll(); + + String separator = String.format("%-60s", "").replace(' ', '='); + + System.out.println(separator); + System.out.printf("%-30s %-30s%n", "Author Name", "Email"); + System.out.println(separator); + + for (Author author : authors) { + System.out.printf("%-30s %-30s%n", author.getName(), author.getEmail()); + } + + System.out.println(separator); + } + + + private void issueBook() { + String usn = prompt("Enter USN: "); + String isbn = prompt("Enter ISBN: "); + + try { + issueService.issueBook(usn, isbn); + System.out.println("Book issued successfully!"); + } catch (IllegalArgumentException | IllegalStateException e) { + System.out.println("Error: " + e.getMessage()); + } + } + + private void listAllBooksByUSN() { + String usn = prompt("Enter USN: "); + Issue issue = issueService.findIssueByStudentUsn(usn); + if (issue != null) { + System.out.println("Book found: " + issue.getIssueBook()); + } else { + System.out.println("No books found for this USN."); + } + } + + private String prompt(String message) { + System.out.print(message); + return scanner.nextLine().trim(); + } + public static void main(String[] args) { + ConfigurableApplicationContext context = SpringApplication.run(HomeworkLibraryApplication.class, args); + + HomeworkLibraryApplication app = context.getBean(HomeworkLibraryApplication.class); + + app.runMenu(); + + SpringApplication.exit(context); + + } + +} diff --git a/src/main/java/com/example/homework_library/models/Author.java b/src/main/java/com/example/homework_library/models/Author.java new file mode 100644 index 00000000..2a8d50a5 --- /dev/null +++ b/src/main/java/com/example/homework_library/models/Author.java @@ -0,0 +1,73 @@ +package com.example.homework_library.models; + +import jakarta.persistence.*; + +@Entity +@Table(name = "author") +public class Author { + + @Id + @GeneratedValue(strategy = jakarta.persistence.GenerationType.IDENTITY) + private int authorId; + + @Column(name = "name") + private String name; + + @Column(name = "email") + private String email; + + @OneToOne + @JoinColumn(name = "author_book", referencedColumnName = "isbn") + private Book authorBook; + + public Author() { + } + + public Author(String name, String email, Book authorBook) { + setName(name); + setEmail(email); + setAuthorBook(authorBook); + } + + public int getAuthorId() { + return authorId; + } + + public void setAuthorId(int authorId) { + this.authorId = authorId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Book getAuthorBook() { + return authorBook; + } + + public void setAuthorBook(Book authorBook) { + this.authorBook = authorBook; + } + + @Override + public String toString() { + return "Author {\n" + + " authorId=" + authorId + ",\n" + + " name='" + name + "',\n" + + " email='" + email + "',\n" + + " authorBook=" + authorBook + "\n" + + "}"; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/homework_library/models/Book.java b/src/main/java/com/example/homework_library/models/Book.java new file mode 100644 index 00000000..8d3b4a46 --- /dev/null +++ b/src/main/java/com/example/homework_library/models/Book.java @@ -0,0 +1,76 @@ +package com.example.homework_library.models; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name = "book") +public class Book { + + @Id + private String isbn; + + @Column(name = "title") + private String title; + + @Column(name = "category") + private String category; + + @Column(name = "quantity") + private int quantity; + + public Book() { + + } + + public Book(String isbn, String title, String category, int quantity) { + setIsbn(isbn); + setTitle(title); + setCategory(category); + setQuantity(quantity); + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getCategory() { + return category; + } + + public void setCategory(String category) { + this.category = category; + } + + public int getQuantity() { + return quantity; + } + + public void setQuantity(int quantity) { + this.quantity = quantity; + } + + @Override + public String toString() { + return "Book {\n" + + " isbn='" + isbn + "',\n" + + " title='" + title + "',\n" + + " category='" + category + "',\n" + + " quantity=" + quantity + "\n" + + "}"; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/homework_library/models/Issue.java b/src/main/java/com/example/homework_library/models/Issue.java new file mode 100644 index 00000000..a67b14c5 --- /dev/null +++ b/src/main/java/com/example/homework_library/models/Issue.java @@ -0,0 +1,87 @@ +package com.example.homework_library.models; + +import jakarta.persistence.*; + +@Entity +@Table(name = "issue") +public class Issue { + + @Id + @GeneratedValue(strategy = jakarta.persistence.GenerationType.IDENTITY) + private int issueId; + + @Column(name = "issue_date") + private String issueDate; + + @Column(name = "return_date") + private String returnDate; + + @OneToOne + @JoinColumn(name = "issue_student", referencedColumnName = "usn") + private Student issueStudent; + + @OneToOne + @JoinColumn(name = "issue_book", referencedColumnName = "isbn") + private Book issueBook; + + public Issue() { + } + + public Issue(String issueDate, String returnDate, Student issueStudent, Book issueBook) { + setIssueDate(issueDate); + setReturnDate(returnDate); + setIssueStudent(issueStudent); + setIssueBook(issueBook); + } + + public int getIssueId() { + return issueId; + } + + public void setIssueId(int issueId) { + this.issueId = issueId; + } + + public String getIssueDate() { + return issueDate; + } + + public void setIssueDate(String issueDate) { + this.issueDate = issueDate; + } + + public String getReturnDate() { + return returnDate; + } + + public void setReturnDate(String returnDate) { + this.returnDate = returnDate; + } + + public Student getIssueStudent() { + return issueStudent; + } + + public void setIssueStudent(Student issueStudent) { + this.issueStudent = issueStudent; + } + + public Book getIssueBook() { + return issueBook; + } + + public void setIssueBook(Book issueBook) { + this.issueBook = issueBook; + } + + @Override + public String toString() { + return "Issue {\n" + + " issueId=" + issueId + ",\n" + + " issueDate='" + issueDate + "',\n" + + " returnDate='" + returnDate + "',\n" + + " issueStudent=" + issueStudent + ",\n" + + " issueBook=" + issueBook + "\n" + + "}"; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/homework_library/models/Student.java b/src/main/java/com/example/homework_library/models/Student.java new file mode 100644 index 00000000..0d5229ea --- /dev/null +++ b/src/main/java/com/example/homework_library/models/Student.java @@ -0,0 +1,49 @@ +package com.example.homework_library.models; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; + +@Entity +@Table(name = "student") +public class Student { + + @Id + private String usn; + + @Column(name = "name") + private String name; + + public Student() { + } + + public String getUsn() { + return usn; + } + + public Student(String usn, String name) { + setUsn(usn); + setName(name); + } + + public void setUsn(String usn) { + this.usn = usn; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "Student {\n" + + " usn='" + usn + "',\n" + + " name='" + name + "'\n" + + "}"; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/homework_library/repositories/AuthorRepository.java b/src/main/java/com/example/homework_library/repositories/AuthorRepository.java new file mode 100644 index 00000000..7891bc73 --- /dev/null +++ b/src/main/java/com/example/homework_library/repositories/AuthorRepository.java @@ -0,0 +1,24 @@ +package com.example.homework_library.repositories; + +import com.example.homework_library.models.Author; +import com.example.homework_library.models.Book; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface AuthorRepository extends JpaRepository { + + // Book findByIsbn(String isbn); + Author findByName(String authorName); + + List findAll(); + + + + + +} + diff --git a/src/main/java/com/example/homework_library/repositories/BookRepository.java b/src/main/java/com/example/homework_library/repositories/BookRepository.java new file mode 100644 index 00000000..d6daf452 --- /dev/null +++ b/src/main/java/com/example/homework_library/repositories/BookRepository.java @@ -0,0 +1,29 @@ +package com.example.homework_library.repositories; + +import com.example.homework_library.models.Author; +import com.example.homework_library.models.Book; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface BookRepository extends JpaRepository { + + Book findByTitle(String title); + + List findByCategory(String category); + + @Query("SELECT b FROM Book b") + List findAllBooksAndAuthors(); + + Book findByIsbn(String isbn); + + + + + + + +} diff --git a/src/main/java/com/example/homework_library/repositories/IssuesRepository.java b/src/main/java/com/example/homework_library/repositories/IssuesRepository.java new file mode 100644 index 00000000..eb321d3c --- /dev/null +++ b/src/main/java/com/example/homework_library/repositories/IssuesRepository.java @@ -0,0 +1,19 @@ +package com.example.homework_library.repositories; + +import com.example.homework_library.models.Issue; +import com.example.homework_library.models.Student; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface IssuesRepository extends JpaRepository { + + //List findIssuesByIssueStudent_Usn(String issueStudentUsn); + Issue findIssuesByIssueStudent_Usn(String issueStudentUsn); + Issue findIssuesByIssueBook_Isbn(String issueBookIsbn); + boolean existsByIssueStudent_Usn(String usn); + boolean existsByIssueBook_Isbn(String isbn); + +} diff --git a/src/main/java/com/example/homework_library/repositories/StudentRepository.java b/src/main/java/com/example/homework_library/repositories/StudentRepository.java new file mode 100644 index 00000000..a65f3d74 --- /dev/null +++ b/src/main/java/com/example/homework_library/repositories/StudentRepository.java @@ -0,0 +1,13 @@ +package com.example.homework_library.repositories; + +import com.example.homework_library.models.Student; +import jdk.jfr.Registered; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface StudentRepository extends JpaRepository { + + Student findByName(String studentName); + Student findStudentByUsn(String usn); +} diff --git a/src/main/java/com/example/homework_library/services/AuthorService.java b/src/main/java/com/example/homework_library/services/AuthorService.java new file mode 100644 index 00000000..572bbd4d --- /dev/null +++ b/src/main/java/com/example/homework_library/services/AuthorService.java @@ -0,0 +1,31 @@ +package com.example.homework_library.services; + +import com.example.homework_library.models.Author; +import com.example.homework_library.models.Book; +import com.example.homework_library.repositories.AuthorRepository; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class AuthorService { + + private final AuthorRepository authorRepository; + + public AuthorService(AuthorRepository authorRepository) { + this.authorRepository = authorRepository; + } + + public Author addAuthor(String name, String email, Book book) { + Author author = new Author(name, email, book); + return authorRepository.save(author); + } + + public List findAll() { + return authorRepository.findAll(); + } + + public Author findAuthorByName(String name) { + return authorRepository.findByName(name); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/homework_library/services/BookService.java b/src/main/java/com/example/homework_library/services/BookService.java new file mode 100644 index 00000000..b24beccb --- /dev/null +++ b/src/main/java/com/example/homework_library/services/BookService.java @@ -0,0 +1,53 @@ +package com.example.homework_library.services; + +import com.example.homework_library.models.Author; +import com.example.homework_library.models.Book; +import com.example.homework_library.repositories.AuthorRepository; +import com.example.homework_library.repositories.BookRepository; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class BookService { + + private final BookRepository bookRepository; + private final AuthorRepository authorRepository; + + public BookService(BookRepository bookRepository, AuthorRepository authorRepository) { + this.bookRepository = bookRepository; + this.authorRepository = authorRepository; + } + + public void addBook(String isbn, String title, String category, String authorName, String mail, int booksNumber) { + Book book = new Book(isbn, title, category, booksNumber); + Author author = new Author(authorName, mail, book); + + bookRepository.save(book); + authorRepository.save(author); + } + + public Book searchBookByTitle(String title) { + return bookRepository.findByTitle(title); + } + + public List listAllBooks() { + return bookRepository.findAllBooksAndAuthors(); + } + + public List searchBooksByCategory(String category) { + return bookRepository.findByCategory(category); + } + + public Book findBookByAuthor(String authorName) { + Author author = authorRepository.findByName(authorName); + if (author != null) { + return author.getAuthorBook(); + } + return null; + } + + public Book searchBookByIsbn(String isbn) { + return bookRepository.findByIsbn(isbn); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/homework_library/services/IssueService.java b/src/main/java/com/example/homework_library/services/IssueService.java new file mode 100644 index 00000000..a434761c --- /dev/null +++ b/src/main/java/com/example/homework_library/services/IssueService.java @@ -0,0 +1,70 @@ +package com.example.homework_library.services; + +import com.example.homework_library.models.Book; +import com.example.homework_library.models.Issue; +import com.example.homework_library.models.Student; +import com.example.homework_library.repositories.BookRepository; +import com.example.homework_library.repositories.IssuesRepository; +import com.example.homework_library.repositories.StudentRepository; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +@Service +public class IssueService { + + private final IssuesRepository issuesRepository; + private final StudentRepository studentRepository; + private final BookRepository bookRepository; + + public IssueService(IssuesRepository issuesRepository,StudentRepository studentRepository, BookRepository bookRepository) { + this.issuesRepository = issuesRepository; + this.studentRepository = studentRepository; + this.bookRepository = bookRepository; + } + + public void issueBook(String usn, String isbn) { + // Buscar el estudiante por USN + Student student = studentRepository.findStudentByUsn(usn); + if (student == null) { + throw new IllegalArgumentException("Student not found with USN: " + usn); + } + + // Buscar el libro por ISBN + Book book = bookRepository.findByIsbn(isbn); + if (book == null) { + throw new IllegalArgumentException("Book not found with ISBN: " + isbn); + } + + // Validar si ya existe un préstamo asociado al estudiante o al libro + if (issuesRepository.existsByIssueStudent_Usn(usn)) { + throw new IllegalStateException("There is already an issue associated with this USN."); + } + + if (issuesRepository.existsByIssueBook_Isbn(isbn)) { + throw new IllegalStateException("There is already an issue associated with this ISBN."); + } + + // Crear y guardar el préstamo + Issue issue = new Issue(getDate(), getExpiredDate(), student, book); + issuesRepository.save(issue); + } + + + public Issue findIssueByStudentUsn(String usn) { + return issuesRepository.findIssuesByIssueStudent_Usn(usn); + } + + private String getDate() { + LocalDate actualDate = LocalDate.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + return actualDate.format(formatter); + } + + private String getExpiredDate() { + LocalDate actualDate = LocalDate.now(); + LocalDate datePlusWeek = actualDate.plusWeeks(1); + return datePlusWeek.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/homework_library/services/StudentService.java b/src/main/java/com/example/homework_library/services/StudentService.java new file mode 100644 index 00000000..a0a0e22a --- /dev/null +++ b/src/main/java/com/example/homework_library/services/StudentService.java @@ -0,0 +1,25 @@ +package com.example.homework_library.services; + +import com.example.homework_library.models.Student; +import com.example.homework_library.repositories.StudentRepository; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class StudentService { + + private final StudentRepository studentRepository; + + public StudentService(StudentRepository studentRepository) { + this.studentRepository = studentRepository; + } + + public Student findStudentByUsn(String usn) { + return studentRepository.findStudentByUsn(usn); + } + + public List listAllStudents() { + return studentRepository.findAll(); + } +} \ No newline at end of file diff --git a/src/test/java/com/example/homework_library/services/BookServiceTest.java b/src/test/java/com/example/homework_library/services/BookServiceTest.java new file mode 100644 index 00000000..eff308f8 --- /dev/null +++ b/src/test/java/com/example/homework_library/services/BookServiceTest.java @@ -0,0 +1,99 @@ +package com.example.homework_library.services; + +import com.example.homework_library.models.Author; +import com.example.homework_library.models.Book; +import com.example.homework_library.repositories.AuthorRepository; +import com.example.homework_library.repositories.BookRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class BookServiceTest { + + @Mock + private BookRepository bookRepository; + + @Mock + private AuthorRepository authorRepository; + + @InjectMocks + private BookService bookService; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void testAddBook() { + // Arrange + String isbn = "123"; + String title = "Test Book"; + String category = "Fiction"; + String authorName = "John Doe"; + String mail = "john@example.com"; + int booksNumber = 10; + + // Act + bookService.addBook(isbn, title, category, authorName, mail, booksNumber); + + // Assert + ArgumentCaptor bookCaptor = ArgumentCaptor.forClass(Book.class); + ArgumentCaptor authorCaptor = ArgumentCaptor.forClass(Author.class); + + verify(bookRepository, times(1)).save(bookCaptor.capture()); + verify(authorRepository, times(1)).save(authorCaptor.capture()); + + Book capturedBook = bookCaptor.getValue(); + Author capturedAuthor = authorCaptor.getValue(); + + assertEquals(isbn, capturedBook.getIsbn()); + assertEquals(title, capturedBook.getTitle()); + assertEquals(category, capturedBook.getCategory()); + assertEquals(booksNumber, capturedBook.getQuantity()); + + assertEquals(authorName, capturedAuthor.getName()); + assertEquals(mail, capturedAuthor.getEmail()); + assertEquals(capturedBook, capturedAuthor.getAuthorBook()); + } + + @Test + void testSearchBookByTitle() { + Book book = new Book("123", "Test Book", "Fiction", 10); + when(bookRepository.findByTitle("Test Book")).thenReturn(book); + + Book result = bookService.searchBookByTitle("Test Book"); + + assertNotNull(result); + assertEquals("Test Book", result.getTitle()); + } + + @Test + void testListAllBooks() { + when(bookRepository.findAllBooksAndAuthors()).thenReturn(List.of(new Book("123", "Test Book", "Fiction", 10))); + + List books = bookService.listAllBooks(); + + assertFalse(books.isEmpty()); + assertEquals(1, books.size()); + } + + @Test + void testSearchBookByIsbn() { + Book book = new Book("123", "Test Book", "Fiction", 10); + when(bookRepository.findByIsbn("123")).thenReturn(book); + + Book result = bookService.searchBookByIsbn("123"); + + assertNotNull(result); + assertEquals("123", result.getIsbn()); + } +} \ No newline at end of file diff --git a/src/test/java/com/example/homework_library/services/IssueServiceTest.java b/src/test/java/com/example/homework_library/services/IssueServiceTest.java new file mode 100644 index 00000000..b126969b --- /dev/null +++ b/src/test/java/com/example/homework_library/services/IssueServiceTest.java @@ -0,0 +1,61 @@ +package com.example.homework_library.services; + +import com.example.homework_library.models.Book; +import com.example.homework_library.models.Issue; +import com.example.homework_library.models.Student; +import com.example.homework_library.repositories.BookRepository; +import com.example.homework_library.repositories.IssuesRepository; +import com.example.homework_library.repositories.StudentRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class IssueServiceTest { + + @Mock + private IssuesRepository issuesRepository; + + @Mock + private StudentRepository studentRepository; + + @Mock + private BookRepository bookRepository; + + @InjectMocks + private IssueService issueService; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void testIssueBook() { + Student student = new Student("USN123", "John Doe"); + Book book = new Book("123", "Test Book", "Fiction", 10); + + when(studentRepository.findStudentByUsn("USN123")).thenReturn(student); + when(bookRepository.findByIsbn("123")).thenReturn(book); + when(issuesRepository.existsByIssueStudent_Usn("USN123")).thenReturn(false); + when(issuesRepository.existsByIssueBook_Isbn("123")).thenReturn(false); + + issueService.issueBook("USN123", "123"); + + verify(issuesRepository, times(1)).save(any(Issue.class)); + } + + @Test + void testFindIssueByStudentUsn() { + Issue issue = new Issue("2023-10-01", "2023-10-08", new Student(), new Book()); + when(issuesRepository.findIssuesByIssueStudent_Usn("USN123")).thenReturn(issue); + + Issue result = issueService.findIssueByStudentUsn("USN123"); + + assertNotNull(result); + } +} \ No newline at end of file diff --git a/src/test/java/com/example/homework_library/services/StudentServiceTest.java b/src/test/java/com/example/homework_library/services/StudentServiceTest.java new file mode 100644 index 00000000..d018dfe8 --- /dev/null +++ b/src/test/java/com/example/homework_library/services/StudentServiceTest.java @@ -0,0 +1,49 @@ +package com.example.homework_library.services; + +import com.example.homework_library.models.Student; +import com.example.homework_library.repositories.StudentRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class StudentServiceTest { + + @Mock + private StudentRepository studentRepository; + + @InjectMocks + private StudentService studentService; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void testFindStudentByUsn() { + Student student = new Student("USN123", "John Doe"); + when(studentRepository.findStudentByUsn("USN123")).thenReturn(student); + + Student result = studentService.findStudentByUsn("USN123"); + + assertNotNull(result); + assertEquals("USN123", result.getUsn()); + } + + @Test + void testListAllStudents() { + when(studentRepository.findAll()).thenReturn(List.of(new Student("USN123", "John Doe"))); + + List students = studentService.listAllStudents(); + + assertFalse(students.isEmpty()); + assertEquals(1, students.size()); + } +} \ No newline at end of file