From dc26f2f873735b2d6b1600ef287d58fcb243f3bf Mon Sep 17 00:00:00 2001 From: Johan Date: Mon, 22 Dec 2025 10:59:56 +0100 Subject: [PATCH 1/8] Push, Co-authored-by: Adam Majava Co-authored-by: Emma Travljanin --- Dockerfile | 9 + docker-compose.yml | 48 +++++ musicdb.trace.db | 9 + pom.xml | 56 +++--- src/main/java/org/example/Main.java | 198 ++++++++++++++++++++ src/main/java/org/example/model/Album.java | 44 +++++ src/main/java/org/example/model/Artist.java | 33 ++++ src/main/java/org/example/model/Song.java | 36 ++++ src/main/resources/META-INF/persistence.xml | 13 ++ 9 files changed, 415 insertions(+), 31 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 musicdb.trace.db create mode 100644 src/main/java/org/example/Main.java create mode 100644 src/main/java/org/example/model/Album.java create mode 100644 src/main/java/org/example/model/Artist.java create mode 100644 src/main/java/org/example/model/Song.java create mode 100644 src/main/resources/META-INF/persistence.xml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..4f7a9f20 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM maven:3.8-openjdk-17 AS builder +WORKDIR /app +COPY pom.xml . +COPY src ./src +RUN mvn clean package -DskipTests + +FROM openjdk:17-jdk-slim +COPY --from=builder /app/target/*.jar app.jar +ENTRYPOINT ["java", "-jar", "app.jar"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..de625a81 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,48 @@ +version: '3.8' + +services: + # MySQL Database + mysql-db: + image: mysql:8.0 + container_name: music-mysql + restart: always + environment: + MYSQL_ROOT_PASSWORD: rootpassword + MYSQL_DATABASE: musicdb + MYSQL_USER: musicuser + MYSQL_PASSWORD: musicpass + ports: + - "3306:3306" + volumes: + - mysql-data:/var/lib/mysql + - ./mysql-init.sql:/docker-entrypoint-initdb.d/init.sql # Optional + networks: + - music-network + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + timeout: 20s + retries: 10 + + # Optional: phpMyAdmin för att hantera databasen + phpmyadmin: + image: phpmyadmin/phpmyadmin + container_name: music-phpmyadmin + restart: always + environment: + PMA_HOST: mysql-db + PMA_PORT: 3306 + UPLOAD_LIMIT: 256M + ports: + - "8080:80" + depends_on: + - mysql-db + networks: + - music-network + +networks: + music-network: + driver: bridge + +volumes: + mysql-data: + driver: local diff --git a/musicdb.trace.db b/musicdb.trace.db new file mode 100644 index 00000000..3dc574c5 --- /dev/null +++ b/musicdb.trace.db @@ -0,0 +1,9 @@ +2025-12-16 15:54:24.333089+01:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "create table Album (id bigint generated by default as identity, title varchar(255), [*]year integer not null, artist_id bigint, primary key (id))"; expected "identifier"; SQL statement: +create table Album (id bigint generated by default as identity, title varchar(255), year integer not null, artist_id bigint, primary key (id)) [42001-224] +2025-12-16 15:54:24.344107+01:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "ALBUM" not found; SQL statement: +alter table Album add constraint FKeornxb63o72l560qifpvd6ty foreign key (artist_id) references Artist [42102-224] +2025-12-16 15:54:24.345111+01:00 jdbc[3]: exception +org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "ALBUM" not found; SQL statement: +alter table Song add constraint FK5i04cpyv4w83t78ui446eelht foreign key (album_id) references Album [42102-224] diff --git a/pom.xml b/pom.xml index 909503d0..657bee08 100644 --- a/pom.xml +++ b/pom.xml @@ -9,46 +9,40 @@ 1.0-SNAPSHOT - 25 + 17 UTF-8 - 6.0.1 - 3.27.6 - 5.21.0 + 5.6.15.Final + 2.2.224 + + - org.junit.jupiter - junit-jupiter - ${junit.jupiter.version} - test + org.hibernate + hibernate-core + ${hibernate.version} + + - org.assertj - assertj-core - ${assertj.core.version} - test + javax.persistence + javax.persistence-api + 2.2 + + + + com.h2database + h2 + ${h2.version} + + + - org.mockito - mockito-junit-jupiter - ${mockito.version} + org.junit.jupiter + junit-jupiter + 5.10.0 test - - org.hibernate.orm - hibernate-core - 7.2.0.Final - - - com.mysql - mysql-connector-j - 9.5.0 - runtime - - - io.github.classgraph - classgraph - 4.8.184 - diff --git a/src/main/java/org/example/Main.java b/src/main/java/org/example/Main.java new file mode 100644 index 00000000..f49e1ec5 --- /dev/null +++ b/src/main/java/org/example/Main.java @@ -0,0 +1,198 @@ +package org.example; + +import org.example.model.Artist; +import org.example.model.Album; +import org.example.model.Song; + +import javax.persistence.*; +import java.util.List; +import java.util.Scanner; + +public class Main { + static EntityManager em; + static Scanner scan = new Scanner(System.in); + + public static void main(String[] args) { + // Starta databas + EntityManagerFactory emf = Persistence.createEntityManagerFactory("musicPU"); + em = emf.createEntityManager(); + + System.out.println(" VÄLKOMMEN TILL MUSIKAPPEN "); + + // meny + boolean running = true; + while(running) { + System.out.println("\n=== HUVUDMENY ==="); + System.out.println("1. Lägg till artist"); + System.out.println("2. Visa alla artister"); + System.out.println("3. Lägg till album"); + System.out.println("4. Lägg till låt"); + System.out.println("5. Visa all musik"); + System.out.println("0. Avsluta"); + System.out.print("Välj: "); + + int val = scan.nextInt(); + scan.nextLine(); // Rensa + + switch(val) { + case 1: addArtist(); break; + case 2: showArtists(); break; + case 3: addAlbum(); break; + case 4: addSong(); break; + case 5: showAllMusic(); break; + case 0: + running = false; + System.out.println(" Hej då!"); + break; + default: + System.out.println(" Ogiltigt val!"); + } + } + + em.close(); + emf.close(); + scan.close(); + } + + // 1. lägg till artist + static void addArtist() { + System.out.print("Artist namn: "); + String name = scan.nextLine(); + + em.getTransaction().begin(); + Artist artist = new Artist(name); + em.persist(artist); + em.getTransaction().commit(); + + System.out.println("✅ Artist tillagd!"); + } + + // 2. visa alla artister + static void showArtists() { + List artists = em.createQuery("SELECT a FROM Artist a", Artist.class).getResultList(); + + System.out.println("\n=== ALLA ARTISTER ==="); + for(Artist a : artists) { + System.out.println("- " + a.getName() + " (ID: " + a.getId() + ")"); + } + System.out.println("====================="); + } + + // 3. lägg till album + static void addAlbum() { + // visa alla artister först + List artists = em.createQuery("SELECT a FROM Artist a", Artist.class).getResultList(); + + if(artists.isEmpty()) { + System.out.println(" Inga artister finns. Lägg till artist först. "); + return; + } + + System.out.println("\n--- Välj artist ---"); + for(int i = 0; i < artists.size(); i++) { + System.out.println(i + ". " + artists.get(i).getName()); + } + System.out.print("Välj artist (nummer): "); + int artistIndex = scan.nextInt(); + scan.nextLine(); + + if(artistIndex < 0 || artistIndex >= artists.size()) { + System.out.println(" Ogiltigt val!"); + return; + } + + Artist selectedArtist = artists.get(artistIndex); + + System.out.print("Album titel: "); + String title = scan.nextLine(); + System.out.print("Utgivningsår: "); + int year = scan.nextInt(); + scan.nextLine(); + + em.getTransaction().begin(); + Album album = new Album(title, year); + album.setArtist(selectedArtist); + em.persist(album); + em.getTransaction().commit(); + + System.out.println(" Album tillagt!"); + } + + // 4. lägg till låt + static void addSong() { + // visa alla album först + List albums = em.createQuery("SELECT a FROM Album a", Album.class).getResultList(); + + if(albums.isEmpty()) { + System.out.println(" Inga album finns. Lägg till album först."); + return; + } + + System.out.println("\n--- Välj album ---"); + for(int i = 0; i < albums.size(); i++) { + Album a = albums.get(i); + System.out.println(i + ". " + a.getTitle() + " - " + a.getArtist().getName()); + } + System.out.print("Välj album (nummer): "); + int albumIndex = scan.nextInt(); + scan.nextLine(); + + if(albumIndex < 0 || albumIndex >= albums.size()) { + System.out.println(" Ogiltigt val!"); + return; + } + + Album selectedAlbum = albums.get(albumIndex); + + System.out.print("Låt titel: "); + String title = scan.nextLine(); + System.out.print("Längd i sekunder: "); + int duration = scan.nextInt(); + scan.nextLine(); + + em.getTransaction().begin(); + Song song = new Song(title, duration); + song.setAlbum(selectedAlbum); + em.persist(song); + em.getTransaction().commit(); + + System.out.println(" Låt tillagd!"); + } + + // 5. visa all musik + static void showAllMusic() { + List artists = em.createQuery("SELECT a FROM Artist a", Artist.class).getResultList(); + + System.out.println("\n=== HELA MUSIKBIBLIOTEKET ==="); + + if(artists.isEmpty()) { + System.out.println("Ingen musik finns ännu."); + return; + } + + for(Artist artist : artists) { + System.out.println("\n🎤 ARTIST: " + artist.getName()); + + if(artist.getAlbums().isEmpty()) { + System.out.println(" (Inga album)"); + continue; + } + + for(Album album : artist.getAlbums()) { + System.out.println(" 💿 ALBUM: " + album.getTitle() + " (" + album.getYear() + ")"); + + if(album.getSongs().isEmpty()) { + System.out.println(" (Inga låtar)"); + continue; + } + + for(Song song : album.getSongs()) { + int minutes = song.getDuration() / 60; + int seconds = song.getDuration() % 60; + System.out.println(" 🎶 " + song.getTitle() + " (" + minutes + ":" + String.format("%02d", seconds) + ")"); + } + } + } + System.out.println("=============================="); + } +} diff --git a/src/main/java/org/example/model/Album.java b/src/main/java/org/example/model/Album.java new file mode 100644 index 00000000..195fba9f --- /dev/null +++ b/src/main/java/org/example/model/Album.java @@ -0,0 +1,44 @@ +package org.example.model; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; + +@Entity +public class Album { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String title; + private int releaseYear; + + @ManyToOne + private Artist artist; + + @OneToMany(mappedBy = "album") + private List songs = new ArrayList<>(); + + public Album() {} + + public Album(String title, int year) { + this.title = title; + this.releaseYear = year; + } + + // Get & Set + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + + public int getYear() { return releaseYear; } + public void setYear(int year) { this.releaseYear = year; } + + public Artist getArtist() { return artist; } + public void setArtist(Artist artist) { this.artist = artist; } + + public List getSongs() { return songs; } + public void setSongs(List songs) { this.songs = songs; } +} diff --git a/src/main/java/org/example/model/Artist.java b/src/main/java/org/example/model/Artist.java new file mode 100644 index 00000000..23b00053 --- /dev/null +++ b/src/main/java/org/example/model/Artist.java @@ -0,0 +1,33 @@ +package org.example.model; + +import javax.persistence.*; +import java.util.ArrayList; +import java.util.List; + +@Entity +public class Artist { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + @OneToMany(mappedBy = "artist") + private List albums = new ArrayList<>(); + + public Artist() {} + + public Artist(String name) { + this.name = name; + } + + // Get & Set + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public String getName() { return name; } + public void setName(String name) { this.name = name; } + + public List getAlbums() { return albums; } + public void setAlbums(List albums) { this.albums = albums; } +} diff --git a/src/main/java/org/example/model/Song.java b/src/main/java/org/example/model/Song.java new file mode 100644 index 00000000..2368674e --- /dev/null +++ b/src/main/java/org/example/model/Song.java @@ -0,0 +1,36 @@ +package org.example.model; + +import javax.persistence.*; + +@Entity +public class Song { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String title; + private int duration; // i sekunder + + @ManyToOne + private Album album; + + public Song() {} + + public Song(String title, int duration) { + this.title = title; + this.duration = duration; + } + + // Get & Set + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public String getTitle() { return title; } + public void setTitle(String title) { this.title = title; } + + public int getDuration() { return duration; } + public void setDuration(int duration) { this.duration = duration; } + + public Album getAlbum() { return album; } + public void setAlbum(Album album) { this.album = album; } +} diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml new file mode 100644 index 00000000..00898e1b --- /dev/null +++ b/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + From f8ab0067cb55e11ad739a5d5cdf3328a27547b21 Mon Sep 17 00:00:00 2001 From: Adam Majava Date: Mon, 22 Dec 2025 11:25:04 +0100 Subject: [PATCH 2/8] Reapply "Add persistence configuration for JPA with MySQL" This reverts commit d1cf77abef38acc7292fa5b6ddd490438edc738a. --- src/main/resources/META-INF/persistence.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/resources/META-INF/persistence.xml diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml new file mode 100644 index 00000000..65b7a2e2 --- /dev/null +++ b/src/main/resources/META-INF/persistence.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + From 1681333ad90c62e680a8973437d16aa1ced782fd Mon Sep 17 00:00:00 2001 From: Adam Majava Date: Mon, 22 Dec 2025 11:30:41 +0100 Subject: [PATCH 3/8] Add persistence configuration for JPA with MySQL --- src/main/resources/META-INF/persistence.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml index 65b7a2e2..60a9adfd 100644 --- a/src/main/resources/META-INF/persistence.xml +++ b/src/main/resources/META-INF/persistence.xml @@ -5,6 +5,7 @@ xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_2.xsd"> + From d65b8848d54a53e18a75d767f6cd607f8a6a419a Mon Sep 17 00:00:00 2001 From: Adam Majava Date: Mon, 12 Jan 2026 16:13:57 +0100 Subject: [PATCH 4/8] Add Playlist and PlaylistSong entities with repository methods --- src/main/java/org/example/model/Playlist.java | 45 ++++++++++++++++ .../java/org/example/model/PlaylistSong.java | 51 +++++++++++++++++++ .../repository/PlaylistRepository.java | 44 ++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 src/main/java/org/example/model/Playlist.java create mode 100644 src/main/java/org/example/model/PlaylistSong.java create mode 100644 src/main/java/org/example/repository/PlaylistRepository.java diff --git a/src/main/java/org/example/model/Playlist.java b/src/main/java/org/example/model/Playlist.java new file mode 100644 index 00000000..088bf562 --- /dev/null +++ b/src/main/java/org/example/model/Playlist.java @@ -0,0 +1,45 @@ +package org.example.model; + +import javax.persistence.*; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Entity +public class Playlist { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + private LocalDateTime createdAt; + + @OneToMany(mappedBy = "playlist", cascade = CascadeType.ALL, orphanRemoval = true) + @OrderBy("position ASC") + private List entries = new ArrayList<>(); + + public Playlist() {} + + public Playlist(String name) { + this.name = name; + this.createdAt = LocalDateTime.now(); + } + + public void addSong(Song song, int position) { + PlaylistSong entry = new PlaylistSong(this, song, position); + entries.add(entry); + } + + public void removeSongBySongId(Long songId) { + entries.removeIf(entry -> entry.getSong() != null && songId.equals(entry.getSong().getId())); + } + + // Getters and Setters + public Long getId() { return id; } + public String getName() { return name; } + public LocalDateTime getCreatedAt() { return createdAt; } + public List getEntries() { return entries; } + + public void setName(String name) { this.name = name; } +} diff --git a/src/main/java/org/example/model/PlaylistSong.java b/src/main/java/org/example/model/PlaylistSong.java new file mode 100644 index 00000000..36b74fcc --- /dev/null +++ b/src/main/java/org/example/model/PlaylistSong.java @@ -0,0 +1,51 @@ +package org.example.model; + +import javax.persistence.*; +import java.time.LocalDateTime; + +@Entity +public class PlaylistSong { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne(optional = false, fetch = FetchType.LAZY) + private Playlist playlist; + + @ManyToOne(optional = false, fetch = FetchType.LAZY) + private Song song; + + private int position; + private LocalDateTime addedAt; + + public PlaylistSong() {} + + public PlaylistSong(Playlist playlist, Song song, int position) { + this.playlist = playlist; + this.song = song; + this.position = position; + this.addedAt = LocalDateTime.now(); + } + // Getters and Setters + public Long getId() { + return id; + } + + public Playlist getPlaylist() { + return playlist; + } + + public Song getSong() { + return song; + } + + public int getPosition() { + return position; + } + + public LocalDateTime getAddedAt() { + return addedAt; + } + +} diff --git a/src/main/java/org/example/repository/PlaylistRepository.java b/src/main/java/org/example/repository/PlaylistRepository.java new file mode 100644 index 00000000..b3b42740 --- /dev/null +++ b/src/main/java/org/example/repository/PlaylistRepository.java @@ -0,0 +1,44 @@ +package org.example.repository; + +import org.example.model.Playlist; +import org.example.model.Song; + +import javax.persistence.EntityManager; +import java.util.List; + +public class PlaylistRepository { + + private final EntityManager em; + + public PlaylistRepository(EntityManager em) { + this.em = em; + } + + public Playlist createPlaylist(String name) { + Playlist p = new Playlist(name); + em.persist(p); + return p; + } + + public List findAll() { + return em.createQuery("SELECT p FROM Playlist p ORDER BY p.createdAt DESC", Playlist.class) + .getResultList(); + } + + public void addSong(Long playlistId, Long songId, int position) { + Playlist playlist = em.find(Playlist.class, playlistId); + if (playlist == null) throw new IllegalArgumentException("Playlist with ID " + playlistId + " not found."); + + Song song = em.find(Song.class, songId); + if (song == null) throw new IllegalArgumentException("Song with ID " + songId + " not found."); + + playlist.addSong(song, position); + } + + public void removeSong(Long playlistId, Long songId) { + Playlist playlist = em.find(Playlist.class, playlistId); + if (playlist == null) throw new IllegalArgumentException("Playlist with ID " + playlistId + " not found."); + + playlist.removeSongBySongId(songId); + } +} From 101a2c17ba0a01a983a92b2035fa02e2dc185097 Mon Sep 17 00:00:00 2001 From: Johan Date: Tue, 13 Jan 2026 17:17:25 +0100 Subject: [PATCH 5/8] Remove persistence.xml from git --- .gitignore | 8 ++++++++ docker-compose.yml | 22 +++------------------ mysql-init.sql | 7 +++++++ pom.xml | 16 ++++++--------- src/main/java/org/example/Main.java | 6 +++--- src/main/java/org/example/model/Album.java | 3 ++- src/main/java/org/example/model/Artist.java | 2 +- src/main/java/org/example/model/Song.java | 1 + src/main/resources/META-INF/persistence.xml | 13 ------------ 9 files changed, 31 insertions(+), 47 deletions(-) create mode 100644 mysql-init.sql delete mode 100644 src/main/resources/META-INF/persistence.xml diff --git a/.gitignore b/.gitignore index 6ac465db..bc9e3cc1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,10 @@ target/ /.idea/ +src/main/resources/META-INF/persistence.xml +*.db +*.mv.db +*.trace.db +.idea/ +*.iml +*.iws +target/ diff --git a/docker-compose.yml b/docker-compose.yml index de625a81..14067c43 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,6 @@ version: '3.8' services: - # MySQL Database mysql-db: image: mysql:8.0 container_name: music-mysql @@ -9,21 +8,13 @@ services: environment: MYSQL_ROOT_PASSWORD: rootpassword MYSQL_DATABASE: musicdb - MYSQL_USER: musicuser - MYSQL_PASSWORD: musicpass ports: - - "3306:3306" + - "3306:3306" # DENNA RAD SAKNAS! volumes: - mysql-data:/var/lib/mysql - - ./mysql-init.sql:/docker-entrypoint-initdb.d/init.sql # Optional - networks: - - music-network - healthcheck: - test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] - timeout: 20s - retries: 10 + command: + - --default-authentication-plugin=mysql_native_password - # Optional: phpMyAdmin för att hantera databasen phpmyadmin: image: phpmyadmin/phpmyadmin container_name: music-phpmyadmin @@ -31,17 +22,10 @@ services: environment: PMA_HOST: mysql-db PMA_PORT: 3306 - UPLOAD_LIMIT: 256M ports: - "8080:80" depends_on: - mysql-db - networks: - - music-network - -networks: - music-network: - driver: bridge volumes: mysql-data: diff --git a/mysql-init.sql b/mysql-init.sql new file mode 100644 index 00000000..cb6be394 --- /dev/null +++ b/mysql-init.sql @@ -0,0 +1,7 @@ +CREATE DATABASE IF NOT EXISTS musicdb; +USE musicdb; + + +CREATE USER IF NOT EXISTS 'musicuser'@'%' IDENTIFIED BY 'musicpass'; +GRANT ALL PRIVILEGES ON musicdb.* TO 'musicuser'@'%'; +FLUSH PRIVILEGES; diff --git a/pom.xml b/pom.xml index 657bee08..87a5f80b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,35 +9,31 @@ 1.0-SNAPSHOT - 17 + 17 UTF-8 - 5.6.15.Final - 2.2.224 + 5.6.15.Final + 8.0.33 - org.hibernate hibernate-core ${hibernate.version} - javax.persistence javax.persistence-api 2.2 - - com.h2database - h2 - ${h2.version} + mysql + mysql-connector-java + ${mysql.version} - org.junit.jupiter junit-jupiter diff --git a/src/main/java/org/example/Main.java b/src/main/java/org/example/Main.java index f49e1ec5..ef6c88d5 100644 --- a/src/main/java/org/example/Main.java +++ b/src/main/java/org/example/Main.java @@ -64,7 +64,7 @@ static void addArtist() { em.persist(artist); em.getTransaction().commit(); - System.out.println("✅ Artist tillagd!"); + System.out.println(" Artist tillagd!"); } // 2. visa alla artister @@ -171,7 +171,7 @@ static void showAllMusic() { } for(Artist artist : artists) { - System.out.println("\n🎤 ARTIST: " + artist.getName()); + System.out.println("\n ARTIST: " + artist.getName()); if(artist.getAlbums().isEmpty()) { System.out.println(" (Inga album)"); @@ -179,7 +179,7 @@ static void showAllMusic() { } for(Album album : artist.getAlbums()) { - System.out.println(" 💿 ALBUM: " + album.getTitle() + " (" + album.getYear() + ")"); + System.out.println(" ALBUM: " + album.getTitle() + " (" + album.getYear() + ")"); if(album.getSongs().isEmpty()) { System.out.println(" (Inga låtar)"); diff --git a/src/main/java/org/example/model/Album.java b/src/main/java/org/example/model/Album.java index 195fba9f..8955ea29 100644 --- a/src/main/java/org/example/model/Album.java +++ b/src/main/java/org/example/model/Album.java @@ -14,9 +14,10 @@ public class Album { private int releaseYear; @ManyToOne + @JoinColumn(name = "artist_id") private Artist artist; - @OneToMany(mappedBy = "album") + @OneToMany(mappedBy = "album", cascade = CascadeType.ALL, orphanRemoval = true) private List songs = new ArrayList<>(); public Album() {} diff --git a/src/main/java/org/example/model/Artist.java b/src/main/java/org/example/model/Artist.java index 23b00053..40d98412 100644 --- a/src/main/java/org/example/model/Artist.java +++ b/src/main/java/org/example/model/Artist.java @@ -12,7 +12,7 @@ public class Artist { private String name; - @OneToMany(mappedBy = "artist") + @OneToMany(mappedBy = "artist", cascade = CascadeType.ALL, orphanRemoval = true) private List albums = new ArrayList<>(); public Artist() {} diff --git a/src/main/java/org/example/model/Song.java b/src/main/java/org/example/model/Song.java index 2368674e..40230f69 100644 --- a/src/main/java/org/example/model/Song.java +++ b/src/main/java/org/example/model/Song.java @@ -12,6 +12,7 @@ public class Song { private int duration; // i sekunder @ManyToOne + @JoinColumn(name = "album_id") private Album album; public Song() {} diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml deleted file mode 100644 index 00898e1b..00000000 --- a/src/main/resources/META-INF/persistence.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - From e478e3b6aad63791f30ae70a467605fb2d1a6eb5 Mon Sep 17 00:00:00 2001 From: Johan Date: Tue, 13 Jan 2026 18:32:38 +0100 Subject: [PATCH 6/8] Add example config and fix Docker setup for team --- docker-compose.yml | 4 +- persistence.xml.example | 24 + src/main/java/org/example/Main.java | 469 ++++++++++++++++-- .../repository/AlbumRepository.java | 33 ++ .../repository/ArtistRepository.java | 39 ++ .../repository/PlaylistRepository.java | 12 +- .../repository/SongRepository.java | 45 ++ .../repository/TransactionHelper.java | 40 ++ src/main/java/ui/DisplayHelper.java | 79 +++ src/main/java/ui/InputValidator.java | 52 ++ src/main/java/ui/MenuManager.java | 245 +++++++++ 11 files changed, 985 insertions(+), 57 deletions(-) create mode 100644 persistence.xml.example create mode 100644 src/main/java/persistence/repository/AlbumRepository.java create mode 100644 src/main/java/persistence/repository/ArtistRepository.java rename src/main/java/{org/example => persistence}/repository/PlaylistRepository.java (84%) create mode 100644 src/main/java/persistence/repository/SongRepository.java create mode 100644 src/main/java/persistence/repository/TransactionHelper.java create mode 100644 src/main/java/ui/DisplayHelper.java create mode 100644 src/main/java/ui/InputValidator.java create mode 100644 src/main/java/ui/MenuManager.java diff --git a/docker-compose.yml b/docker-compose.yml index 14067c43..f8afb068 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,8 +8,10 @@ services: environment: MYSQL_ROOT_PASSWORD: rootpassword MYSQL_DATABASE: musicdb + MYSQL_USER: music_app + MYSQL_PASSWORD: music_app_pass ports: - - "3306:3306" # DENNA RAD SAKNAS! + - "3306:3306" volumes: - mysql-data:/var/lib/mysql command: diff --git a/persistence.xml.example b/persistence.xml.example new file mode 100644 index 00000000..38c1aa12 --- /dev/null +++ b/persistence.xml.example @@ -0,0 +1,24 @@ + + + + org.hibernate.jpa.HibernatePersistenceProvider + + org.example.model.Artist + org.example.model.Album + org.example.model.Song + org.example.model.Playlist + org.example.model.PlaylistSong + + + + + + + + + + + + + + diff --git a/src/main/java/org/example/Main.java b/src/main/java/org/example/Main.java index ef6c88d5..8afb9381 100644 --- a/src/main/java/org/example/Main.java +++ b/src/main/java/org/example/Main.java @@ -1,9 +1,7 @@ package org.example; -import org.example.model.Artist; -import org.example.model.Album; -import org.example.model.Song; - +import persistence.repository.*; +import org.example.model.*; import javax.persistence.*; import java.util.List; import java.util.Scanner; @@ -12,34 +10,63 @@ public class Main { static EntityManager em; static Scanner scan = new Scanner(System.in); + static ArtistRepository artistRepo; + static AlbumRepository albumRepo; + static SongRepository songRepo; + static PlaylistRepository playlistRepo; + static TransactionHelper transactionHelper; + public static void main(String[] args) { - // Starta databas EntityManagerFactory emf = Persistence.createEntityManagerFactory("musicPU"); em = emf.createEntityManager(); + artistRepo = new ArtistRepository(em); + albumRepo = new AlbumRepository(em); + songRepo = new SongRepository(em); + playlistRepo = new PlaylistRepository(em); + transactionHelper = new TransactionHelper(em); + System.out.println(" VÄLKOMMEN TILL MUSIKAPPEN "); - // meny boolean running = true; while(running) { System.out.println("\n=== HUVUDMENY ==="); System.out.println("1. Lägg till artist"); System.out.println("2. Visa alla artister"); System.out.println("3. Lägg till album"); - System.out.println("4. Lägg till låt"); - System.out.println("5. Visa all musik"); + System.out.println("4. Visa albums för artist"); + System.out.println("5. Lägg till låt"); + System.out.println("6. Visa låtar för album"); + System.out.println("7. Visa all musik"); + System.out.println("8. Skapa spellista"); + System.out.println("9. Visa alla spellistor"); + System.out.println("10. Lägg till låt i spellista"); + System.out.println("11. Ta bort låt från spellista"); System.out.println("0. Avsluta"); System.out.print("Välj: "); - int val = scan.nextInt(); - scan.nextLine(); // Rensa + int val = 0; + try { + val = scan.nextInt(); + } catch (Exception e) { + System.out.println("Ogiltigt val!"); + scan.nextLine(); + continue; + } + scan.nextLine(); switch(val) { case 1: addArtist(); break; case 2: showArtists(); break; case 3: addAlbum(); break; - case 4: addSong(); break; - case 5: showAllMusic(); break; + case 4: showAlbumsByArtist(); break; + case 5: addSong(); break; + case 6: showSongsByAlbum(); break; + case 7: showAllMusic(); break; + case 8: createPlaylist(); break; + case 9: showPlaylists(); break; + case 10: addSongToPlaylist(); break; + case 11: removeSongFromPlaylist(); break; case 0: running = false; System.out.println(" Hej då!"); @@ -54,37 +81,42 @@ public static void main(String[] args) { scan.close(); } - // 1. lägg till artist static void addArtist() { System.out.print("Artist namn: "); String name = scan.nextLine(); - em.getTransaction().begin(); - Artist artist = new Artist(name); - em.persist(artist); - em.getTransaction().commit(); + if (name.trim().isEmpty()) { + System.out.println("Namn får inte vara tomt!"); + return; + } - System.out.println(" Artist tillagd!"); + transactionHelper.executeInTransaction(() -> { + Artist artist = new Artist(name); + artistRepo.save(artist); + System.out.println(" Artist tillagd med ID: " + artist.getId()); + }); } - // 2. visa alla artister static void showArtists() { - List artists = em.createQuery("SELECT a FROM Artist a", Artist.class).getResultList(); + List artists = artistRepo.findAll(); System.out.println("\n=== ALLA ARTISTER ==="); + if (artists.isEmpty()) { + System.out.println("Inga artister finns."); + return; + } + for(Artist a : artists) { - System.out.println("- " + a.getName() + " (ID: " + a.getId() + ")"); + System.out.println(a.getId() + ". " + a.getName() + + " (" + a.getAlbums().size() + " album)"); } - System.out.println("====================="); } - // 3. lägg till album static void addAlbum() { - // visa alla artister först - List artists = em.createQuery("SELECT a FROM Artist a", Artist.class).getResultList(); + List artists = artistRepo.findAll(); if(artists.isEmpty()) { - System.out.println(" Inga artister finns. Lägg till artist först. "); + System.out.println(" Inga artister finns. Lägg till artist först."); return; } @@ -93,7 +125,15 @@ static void addAlbum() { System.out.println(i + ". " + artists.get(i).getName()); } System.out.print("Välj artist (nummer): "); - int artistIndex = scan.nextInt(); + + int artistIndex = -1; + try { + artistIndex = scan.nextInt(); + } catch (Exception e) { + System.out.println("Ogiltigt val!"); + scan.nextLine(); + return; + } scan.nextLine(); if(artistIndex < 0 || artistIndex >= artists.size()) { @@ -106,22 +146,74 @@ static void addAlbum() { System.out.print("Album titel: "); String title = scan.nextLine(); System.out.print("Utgivningsår: "); - int year = scan.nextInt(); + + int year = 0; + try { + year = scan.nextInt(); + } catch (Exception e) { + System.out.println("Ogiltigt år!"); + scan.nextLine(); + return; + } + scan.nextLine(); + + if (year < 1900 || year > 2100) { + System.out.println("Ogiltigt år! Måste vara mellan 1900-2100."); + return; + } + + final Artist finalArtist = selectedArtist; + final String finalTitle = title; + final int finalYear = year; + + transactionHelper.executeInTransaction(() -> { + Album album = new Album(finalTitle, finalYear); + album.setArtist(finalArtist); + albumRepo.save(album); + System.out.println(" Album tillagt med ID: " + album.getId()); + }); + } + + static void showAlbumsByArtist() { + System.out.print("Artist ID (tryck 0 för att se alla artister): "); + + Long artistId = 0L; + try { + artistId = scan.nextLong(); + } catch (Exception e) { + System.out.println("Ogiltigt ID!"); + scan.nextLine(); + return; + } scan.nextLine(); - em.getTransaction().begin(); - Album album = new Album(title, year); - album.setArtist(selectedArtist); - em.persist(album); - em.getTransaction().commit(); + if (artistId == 0) { + showArtists(); + return; + } - System.out.println(" Album tillagt!"); + Artist artist = artistRepo.findById(artistId); + if (artist == null) { + System.out.println("Artist med ID " + artistId + " finns inte."); + return; + } + + List albums = albumRepo.findByArtistId(artistId); + System.out.println("\n=== ALBUMS AV " + artist.getName() + " ==="); + + if (albums.isEmpty()) { + System.out.println("Inga album för denna artist."); + return; + } + + for(Album a : albums) { + System.out.println(a.getId() + ". " + a.getTitle() + + " (" + a.getYear() + ") - " + a.getSongs().size() + " låtar"); + } } - // 4. lägg till låt static void addSong() { - // visa alla album först - List albums = em.createQuery("SELECT a FROM Album a", Album.class).getResultList(); + List albums = albumRepo.findAll(); if(albums.isEmpty()) { System.out.println(" Inga album finns. Lägg till album först."); @@ -131,10 +223,19 @@ static void addSong() { System.out.println("\n--- Välj album ---"); for(int i = 0; i < albums.size(); i++) { Album a = albums.get(i); - System.out.println(i + ". " + a.getTitle() + " - " + a.getArtist().getName()); + System.out.println(i + ". " + a.getTitle() + " - " + + a.getArtist().getName() + " (" + a.getYear() + ")"); } System.out.print("Välj album (nummer): "); - int albumIndex = scan.nextInt(); + + int albumIndex = -1; + try { + albumIndex = scan.nextInt(); + } catch (Exception e) { + System.out.println("Ogiltigt val!"); + scan.nextLine(); + return; + } scan.nextLine(); if(albumIndex < 0 || albumIndex >= albums.size()) { @@ -147,21 +248,92 @@ static void addSong() { System.out.print("Låt titel: "); String title = scan.nextLine(); System.out.print("Längd i sekunder: "); - int duration = scan.nextInt(); + + int duration = 0; + try { + duration = scan.nextInt(); + } catch (Exception e) { + System.out.println("Ogiltig längd!"); + scan.nextLine(); + return; + } scan.nextLine(); - em.getTransaction().begin(); - Song song = new Song(title, duration); - song.setAlbum(selectedAlbum); - em.persist(song); - em.getTransaction().commit(); + if (duration <= 0) { + System.out.println("Längden måste vara större än 0."); + return; + } + + final Album finalAlbum = selectedAlbum; + final String finalTitle = title; + final int finalDuration = duration; - System.out.println(" Låt tillagd!"); + transactionHelper.executeInTransaction(() -> { + Song song = new Song(finalTitle, finalDuration); + song.setAlbum(finalAlbum); + songRepo.save(song); + System.out.println(" Låt tillagd med ID: " + song.getId()); + }); + } + + static void showSongsByAlbum() { + System.out.print("Album ID (tryck 0 för att se alla album): "); + + Long albumId = 0L; + try { + albumId = scan.nextLong(); + } catch (Exception e) { + System.out.println("Ogiltigt ID!"); + scan.nextLine(); + return; + } + scan.nextLine(); + + if (albumId == 0) { + showAllAlbums(); + return; + } + + Album album = albumRepo.findById(albumId); + if (album == null) { + System.out.println("Album med ID " + albumId + " finns inte."); + return; + } + + List songs = songRepo.findByAlbumId(albumId); + System.out.println("\n=== LÅTAR PÅ \"" + album.getTitle() + "\" ==="); + + if (songs.isEmpty()) { + System.out.println("Inga låtar på detta album."); + return; + } + + for(Song s : songs) { + int minutes = s.getDuration() / 60; + int seconds = s.getDuration() % 60; + System.out.println(s.getId() + ". " + s.getTitle() + + " (" + minutes + ":" + String.format("%02d", seconds) + ")"); + } + } + + static void showAllAlbums() { + List albums = albumRepo.findAll(); + + System.out.println("\n=== ALLA ALBUM ==="); + if (albums.isEmpty()) { + System.out.println("Inga album finns."); + return; + } + + for(Album a : albums) { + System.out.println(a.getId() + ". " + a.getTitle() + + " - " + a.getArtist().getName() + + " (" + a.getYear() + ") - " + a.getSongs().size() + " låtar"); + } } - // 5. visa all musik static void showAllMusic() { - List artists = em.createQuery("SELECT a FROM Artist a", Artist.class).getResultList(); + List artists = artistRepo.findAll(); System.out.println("\n=== HELA MUSIKBIBLIOTEKET ==="); @@ -189,10 +361,209 @@ static void showAllMusic() { for(Song song : album.getSongs()) { int minutes = song.getDuration() / 60; int seconds = song.getDuration() % 60; - System.out.println(" 🎶 " + song.getTitle() + " (" + minutes + ":" + String.format("%02d", seconds) + ")"); + System.out.println(" 🎶 " + song.getTitle() + + " (" + minutes + ":" + String.format("%02d", seconds) + ")"); } } } System.out.println("=============================="); } + + static void createPlaylist() { + System.out.print("Spellista namn: "); + String name = scan.nextLine(); + + if (name.trim().isEmpty()) { + System.out.println("Namn får inte vara tomt!"); + return; + } + + final String finalName = name; + + transactionHelper.executeInTransaction(() -> { + Playlist playlist = playlistRepo.createPlaylist(finalName); + System.out.println(" Spellista skapad med ID: " + playlist.getId()); + }); + } + + static void showPlaylists() { + List playlists = playlistRepo.findAll(); + + System.out.println("\n=== ALLA SPELLISTOR ==="); + if (playlists.isEmpty()) { + System.out.println("Inga spellistor finns."); + return; + } + + for(Playlist p : playlists) { + System.out.println(p.getId() + ". " + p.getName() + + " (skapad: " + p.getCreatedAt() + ") - " + + p.getEntries().size() + " låtar"); + } + } + + static void addSongToPlaylist() { + List playlists = playlistRepo.findAll(); + List songs = songRepo.findAll(); + + if (playlists.isEmpty()) { + System.out.println("Inga spellistor finns. Skapa en först."); + return; + } + + if (songs.isEmpty()) { + System.out.println("Inga låtar finns. Lägg till låtar först."); + return; + } + + System.out.println("\n--- Välj spellista ---"); + for(int i = 0; i < playlists.size(); i++) { + Playlist p = playlists.get(i); + System.out.println(i + ". " + p.getName() + + " (" + p.getEntries().size() + " låtar)"); + } + System.out.print("Välj spellista (nummer): "); + + int playlistIndex = -1; + try { + playlistIndex = scan.nextInt(); + } catch (Exception e) { + System.out.println("Ogiltigt val!"); + scan.nextLine(); + return; + } + scan.nextLine(); + + if (playlistIndex < 0 || playlistIndex >= playlists.size()) { + System.out.println("Ogiltigt val!"); + return; + } + + Playlist playlist = playlists.get(playlistIndex); + + System.out.println("\n--- Välj låt ---"); + for(int i = 0; i < songs.size(); i++) { + Song s = songs.get(i); + System.out.println(i + ". " + s.getTitle() + + " - " + s.getAlbum().getArtist().getName() + + " (" + s.getAlbum().getTitle() + ")"); + } + System.out.print("Välj låt (nummer): "); + + int songIndex = -1; + try { + songIndex = scan.nextInt(); + } catch (Exception e) { + System.out.println("Ogiltigt val!"); + scan.nextLine(); + return; + } + scan.nextLine(); + + if (songIndex < 0 || songIndex >= songs.size()) { + System.out.println("Ogiltigt val!"); + return; + } + + Song song = songs.get(songIndex); + System.out.print("Position i spellistan: "); + + int position = 1; + try { + position = scan.nextInt(); + } catch (Exception e) { + System.out.println("Ogiltig position!"); + scan.nextLine(); + return; + } + scan.nextLine(); + + if (position < 1) { + System.out.println("Position måste vara minst 1."); + return; + } + + final Long finalPlaylistId = playlist.getId(); + final Long finalSongId = song.getId(); + final int finalPosition = position; + + transactionHelper.executeInTransaction(() -> { + playlistRepo.addSong(finalPlaylistId, finalSongId, finalPosition); + System.out.println(" Låt tillagd i spellistan!"); + }); + } + + static void removeSongFromPlaylist() { + List playlists = playlistRepo.findAll(); + + if (playlists.isEmpty()) { + System.out.println("Inga spellistor finns."); + return; + } + + System.out.println("\n--- Välj spellista ---"); + for(int i = 0; i < playlists.size(); i++) { + Playlist p = playlists.get(i); + System.out.println(i + ". " + p.getName() + + " (" + p.getEntries().size() + " låtar)"); + } + System.out.print("Välj spellista (nummer): "); + + int playlistIndex = -1; + try { + playlistIndex = scan.nextInt(); + } catch (Exception e) { + System.out.println("Ogiltigt val!"); + scan.nextLine(); + return; + } + scan.nextLine(); + + if (playlistIndex < 0 || playlistIndex >= playlists.size()) { + System.out.println("Ogiltigt val!"); + return; + } + + Playlist playlist = playlists.get(playlistIndex); + + if (playlist.getEntries().isEmpty()) { + System.out.println("Spellistan är tom."); + return; + } + + System.out.println("\n--- Välj låt att ta bort ---"); + List entries = playlist.getEntries(); + for(int i = 0; i < entries.size(); i++) { + PlaylistSong entry = entries.get(i); + Song song = entry.getSong(); + System.out.println(i + ". " + song.getTitle() + + " (position: " + entry.getPosition() + ")"); + } + System.out.print("Välj låt (nummer): "); + + int songIndex = -1; + try { + songIndex = scan.nextInt(); + } catch (Exception e) { + System.out.println("Ogiltigt val!"); + scan.nextLine(); + return; + } + scan.nextLine(); + + if (songIndex < 0 || songIndex >= entries.size()) { + System.out.println("Ogiltigt val!"); + return; + } + + PlaylistSong entry = entries.get(songIndex); + + final Long finalPlaylistId = playlist.getId(); + final Long finalSongId = entry.getSong().getId(); + + transactionHelper.executeInTransaction(() -> { + playlistRepo.removeSong(finalPlaylistId, finalSongId); + System.out.println(" Låt borttagen från spellistan!"); + }); + } } diff --git a/src/main/java/persistence/repository/AlbumRepository.java b/src/main/java/persistence/repository/AlbumRepository.java new file mode 100644 index 00000000..14265b5f --- /dev/null +++ b/src/main/java/persistence/repository/AlbumRepository.java @@ -0,0 +1,33 @@ +package persistence.repository; + +import org.example.model.Album; +import org.example.model.Artist; +import javax.persistence.EntityManager; +import java.util.List; + +public class AlbumRepository { + private final EntityManager em; + + public AlbumRepository(EntityManager em) { + this.em = em; + } + + public Album save(Album album) { + em.persist(album); + return album; + } + + public Album findById(Long id) { + return em.find(Album.class, id); + } + + public List findAll() { + return em.createQuery("SELECT a FROM Album a", Album.class).getResultList(); + } + + public List findByArtistId(Long artistId) { + return em.createQuery("SELECT a FROM Album a WHERE a.artist.id = :artistId", Album.class) + .setParameter("artistId", artistId) + .getResultList(); + } +} diff --git a/src/main/java/persistence/repository/ArtistRepository.java b/src/main/java/persistence/repository/ArtistRepository.java new file mode 100644 index 00000000..4f40ac8e --- /dev/null +++ b/src/main/java/persistence/repository/ArtistRepository.java @@ -0,0 +1,39 @@ +package persistence.repository; + +import org.example.model.Artist; +import javax.persistence.EntityManager; +import java.util.List; + +public class ArtistRepository { + private final EntityManager em; + + public ArtistRepository(EntityManager em) { + this.em = em; + } + + public Artist save(Artist artist) { + em.persist(artist); + return artist; + } + + public Artist findById(Long id) { + return em.find(Artist.class, id); + } + + public List findAll() { + return em.createQuery("SELECT a FROM Artist a", Artist.class).getResultList(); + } + + public boolean deleteArtist(Long id) { + try { + Artist artist = findById(id); + if (artist != null) { + em.remove(artist); + return true; + } + return false; + } catch (Exception e) { + return false; + } + } +} diff --git a/src/main/java/org/example/repository/PlaylistRepository.java b/src/main/java/persistence/repository/PlaylistRepository.java similarity index 84% rename from src/main/java/org/example/repository/PlaylistRepository.java rename to src/main/java/persistence/repository/PlaylistRepository.java index b3b42740..c377bb29 100644 --- a/src/main/java/org/example/repository/PlaylistRepository.java +++ b/src/main/java/persistence/repository/PlaylistRepository.java @@ -1,13 +1,11 @@ -package org.example.repository; +package persistence.repository; import org.example.model.Playlist; import org.example.model.Song; - import javax.persistence.EntityManager; import java.util.List; public class PlaylistRepository { - private final EntityManager em; public PlaylistRepository(EntityManager em) { @@ -22,22 +20,22 @@ public Playlist createPlaylist(String name) { public List findAll() { return em.createQuery("SELECT p FROM Playlist p ORDER BY p.createdAt DESC", Playlist.class) - .getResultList(); + .getResultList(); } public void addSong(Long playlistId, Long songId, int position) { Playlist playlist = em.find(Playlist.class, playlistId); - if (playlist == null) throw new IllegalArgumentException("Playlist with ID " + playlistId + " not found."); + if (playlist == null) throw new IllegalArgumentException("Playlist not found."); Song song = em.find(Song.class, songId); - if (song == null) throw new IllegalArgumentException("Song with ID " + songId + " not found."); + if (song == null) throw new IllegalArgumentException("Song not found."); playlist.addSong(song, position); } public void removeSong(Long playlistId, Long songId) { Playlist playlist = em.find(Playlist.class, playlistId); - if (playlist == null) throw new IllegalArgumentException("Playlist with ID " + playlistId + " not found."); + if (playlist == null) throw new IllegalArgumentException("Playlist not found."); playlist.removeSongBySongId(songId); } diff --git a/src/main/java/persistence/repository/SongRepository.java b/src/main/java/persistence/repository/SongRepository.java new file mode 100644 index 00000000..d87ed6e5 --- /dev/null +++ b/src/main/java/persistence/repository/SongRepository.java @@ -0,0 +1,45 @@ +package persistence.repository; + +import org.example.model.Song; +import javax.persistence.EntityManager; +import java.util.List; + +public class SongRepository { + private final EntityManager em; + + public SongRepository(EntityManager em) { + this.em = em; + } + + public Song save(Song song) { + em.persist(song); + return song; + } + + public Song findById(Long id) { + return em.find(Song.class, id); + } + + public List findAll() { + return em.createQuery("SELECT s FROM Song s", Song.class).getResultList(); + } + + public List findByAlbumId(Long albumId) { + return em.createQuery("SELECT s FROM Song s WHERE s.album.id = :albumId", Song.class) + .setParameter("albumId", albumId) + .getResultList(); + } + + public boolean deleteSong(Long id) { + try { + Song song = findById(id); + if (song != null) { + em.remove(song); + return true; + } + return false; + } catch (Exception e) { + return false; + } + } +} diff --git a/src/main/java/persistence/repository/TransactionHelper.java b/src/main/java/persistence/repository/TransactionHelper.java new file mode 100644 index 00000000..20d6882d --- /dev/null +++ b/src/main/java/persistence/repository/TransactionHelper.java @@ -0,0 +1,40 @@ +package persistence.repository; + +import javax.persistence.EntityManager; + +public class TransactionHelper { + private final EntityManager em; + + public TransactionHelper(EntityManager em) { + this.em = em; + } + + public void beginTransaction() { + if (!em.getTransaction().isActive()) { + em.getTransaction().begin(); + } + } + + public void commitTransaction() { + if (em.getTransaction().isActive()) { + em.getTransaction().commit(); + } + } + + public void rollbackTransaction() { + if (em.getTransaction().isActive()) { + em.getTransaction().rollback(); + } + } + + public void executeInTransaction(Runnable operation) { + try { + beginTransaction(); + operation.run(); + commitTransaction(); + } catch (Exception e) { + rollbackTransaction(); + throw e; + } + } +} diff --git a/src/main/java/ui/DisplayHelper.java b/src/main/java/ui/DisplayHelper.java new file mode 100644 index 00000000..03b1db5e --- /dev/null +++ b/src/main/java/ui/DisplayHelper.java @@ -0,0 +1,79 @@ +package org.example.ui; // eller org.example.UI + +import org.example.model.Artist; +import org.example.model.Album; +import org.example.model.Song; +import java.util.List; + +public class DisplayHelper { + + public static void printArtistList(List artists) { + if (artists.isEmpty()) { + System.out.println("Inga artister hittades."); + return; + } + + System.out.println("\n" + "=".repeat(60)); + System.out.printf("%-4s %-25s %-15s%n", "ID", "NAMN", "ANTAL ALBUM"); + System.out.println("-".repeat(60)); + + for (Artist a : artists) { + System.out.printf("%-4d %-25s %-15d%n", + a.getId(), + truncate(a.getName(), 23), + a.getAlbums().size()); + } + } + + public static void printAlbumList(List albums) { + if (albums.isEmpty()) { + System.out.println("Inga album hittades."); + return; + } + + System.out.println("\n" + "=".repeat(70)); + System.out.printf("%-4s %-25s %-20s %-10s%n", + "ID", "TITEL", "ARTIST", "ÅR"); + System.out.println("-".repeat(70)); + + for (Album a : albums) { + System.out.printf("%-4d %-25s %-20s %-10d%n", + a.getId(), + truncate(a.getTitle(), 23), + truncate(a.getArtist().getName(), 18), + a.getYear()); // ÄNDRA HÄR: getYear() istället för getReleaseYear() + } + } + + public static void printSongList(List songs) { + if (songs.isEmpty()) { + System.out.println("Inga låtar hittades."); + return; + } + + System.out.println("\n" + "=".repeat(80)); + System.out.printf("%-4s %-20s %-25s %-20s %-10s%n", + "ID", "ARTIST", "ALBUM", "LÅT", "LÄNGD"); + System.out.println("-".repeat(80)); + + for (Song s : songs) { + System.out.printf("%-4d %-20s %-25s %-20s %-10s%n", + s.getId(), + truncate(s.getAlbum().getArtist().getName(), 18), + truncate(s.getAlbum().getTitle(), 23), + truncate(s.getTitle(), 18), + formatDuration(s.getDuration())); + } + } + + public static String formatDuration(int seconds) { + int minutes = seconds / 60; + int remainingSeconds = seconds % 60; + return String.format("%d:%02d", minutes, remainingSeconds); + } + + private static String truncate(String text, int maxLength) { + if (text.length() <= maxLength) return text; + return text.substring(0, maxLength - 3) + "..."; + } +} diff --git a/src/main/java/ui/InputValidator.java b/src/main/java/ui/InputValidator.java new file mode 100644 index 00000000..c8a759c1 --- /dev/null +++ b/src/main/java/ui/InputValidator.java @@ -0,0 +1,52 @@ +package org.example.ui; + +import java.util.Scanner; + +public class InputValidator { + + public static int getIntInput(Scanner scanner, String prompt, int min, int max) { + while (true) { + System.out.print(prompt); + try { + int value = scanner.nextInt(); + scanner.nextLine(); // Rensa newline + + if (value >= min && value <= max) { + return value; + } else { + System.out.printf("❌ Måste vara mellan %d och %d. Försök igen.%n", min, max); + } + } catch (Exception e) { + System.out.println("❌ Ogiltigt nummer. Försök igen."); + scanner.nextLine(); // Rensa felaktig input + } + } + } + + public static long getLongInput(Scanner scanner, String prompt) { + while (true) { + System.out.print(prompt); + try { + long value = scanner.nextLong(); + scanner.nextLine(); // Rensa newline + return value; + } catch (Exception e) { + System.out.println("❌ Ogiltigt nummer. Försök igen."); + scanner.nextLine(); // Rensa felaktig input + } + } + } + + public static String getNonEmptyString(Scanner scanner, String prompt) { + while (true) { + System.out.print(prompt); + String input = scanner.nextLine().trim(); + + if (!input.isEmpty()) { + return input; + } else { + System.out.println("❌ Fältet får inte vara tomt. Försök igen."); + } + } + } +} diff --git a/src/main/java/ui/MenuManager.java b/src/main/java/ui/MenuManager.java new file mode 100644 index 00000000..5b814a1f --- /dev/null +++ b/src/main/java/ui/MenuManager.java @@ -0,0 +1,245 @@ +package org.example.ui; + +import persistence.repository.ArtistRepository; +import persistence.repository.AlbumRepository; +import persistence.repository.SongRepository; +import persistence.repository.PlaylistRepository; +import org.example.model.*; +import java.util.List; +import java.util.Scanner; + +public class MenuManager { + private Scanner scanner; + private ArtistRepository artistRepo; + private AlbumRepository albumRepo; + private SongRepository songRepo; + private PlaylistRepository playlistRepo; + + public MenuManager(Scanner scanner, + ArtistRepository artistRepo, + AlbumRepository albumRepo, + SongRepository songRepo, + PlaylistRepository playlistRepo) { + this.scanner = scanner; + this.artistRepo = artistRepo; + this.albumRepo = albumRepo; + this.songRepo = songRepo; + this.playlistRepo = playlistRepo; + } + + //HUVUDMETOD + public void start() { + System.out.println("🎵 VÄLKOMMEN TILL MUSIKAPPEN 🎵"); + + boolean running = true; + while (running) { + System.out.println("\n" + "=".repeat(40)); + System.out.println("=== HUVUDMENY ==="); + System.out.println("1. 🎤 Artister"); + System.out.println("2. 💿 Album"); + System.out.println("3. 🎶 Låtar"); + System.out.println("4. 📋 Spellistor"); + System.out.println("5. 🔍 Sök"); + System.out.println("0. ❌ Avsluta"); + System.out.println("=".repeat(40)); + + int choice = InputValidator.getIntInput(scanner, "Val: ", 0, 5); + + switch (choice) { + case 1: artistMenu(); break; + case 2: albumMenu(); break; + case 3: songMenu(); break; + case 4: playlistMenu(); break; + case 5: searchMenu(); break; + case 0: + running = false; + System.out.println("\n👋 Tack för idag!"); + break; + } + } + } + + // ARTIST-MENY + private void artistMenu() { + boolean inMenu = true; + while (inMenu) { + System.out.println("\n=== ARTIST-MENY ==="); + System.out.println("1. Visa alla artister"); + System.out.println("2. Lägg till ny artist"); + System.out.println("3. Visa artists album"); + System.out.println("4. Ta bort artist"); + System.out.println("0. ← Tillbaka till huvudmeny"); + + int choice = InputValidator.getIntInput(scanner, "Val: ", 0, 4); + + switch (choice) { + case 1: showAllArtists(); break; + case 2: addArtist(); break; + case 3: showArtistAlbums(); break; + case 4: deleteArtist(); break; + case 0: inMenu = false; break; + } + } + } + + // LÅT-MENY (med borttagning) + private void songMenu() { + boolean inMenu = true; + while (inMenu) { + System.out.println("\n=== LÅT-MENY ==="); + System.out.println("1. Visa alla låtar"); + System.out.println("2. Lägg till ny låt"); + System.out.println("3. Ta bort låt"); + System.out.println("0. ← Tillbaka till huvudmeny"); + + int choice = InputValidator.getIntInput(scanner, "Val: ", 0, 3); + + switch (choice) { + case 1: showAllSongs(); break; + case 2: addSong(); break; + case 3: deleteSong(); break; + case 0: inMenu = false; break; + } + } + } + + // METOD FÖR ATT TA BORT LÅT + private void deleteSong() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("TA BORT LÅT"); + System.out.println("=".repeat(40)); + + List songs = songRepo.findAll(); + if (songs.isEmpty()) { + System.out.println("⚠️ Inga låtar finns att ta bort."); + return; + } + + DisplayHelper.printSongList(songs); + + System.out.print("\nAnge ID på låten du vill ta bort: "); + Long songId; + try { + songId = scanner.nextLong(); + scanner.nextLine(); + } catch (Exception e) { + System.out.println("❌ Ogiltigt ID. Ange ett nummer."); + scanner.nextLine(); + return; + } + + Song songToDelete = songRepo.findById(songId); + if (songToDelete == null) { + System.out.println("❌ Ingen låt hittades med ID: " + songId); + return; + } + + System.out.println("\n" + "=".repeat(40)); + System.out.println("BEKRÄFTA BORTTAGNING"); + System.out.println("=".repeat(40)); + System.out.println("Låt: " + songToDelete.getTitle()); + System.out.println("Artist: " + songToDelete.getAlbum().getArtist().getName()); + System.out.println("Album: " + songToDelete.getAlbum().getTitle()); + System.out.println("Längd: " + DisplayHelper.formatDuration(songToDelete.getDuration())); + + System.out.print("\n⚠️ Är du SÄKER på att du vill ta bort denna låt? (JA/nej): "); + String confirmation = scanner.nextLine().trim(); + + if (confirmation.equalsIgnoreCase("JA")) { + boolean success = songRepo.deleteSong(songId); + if (success) { + System.out.println("✅ Låt togs bort!"); + } else { + System.out.println("❌ Kunde inte ta bort låten."); + } + } else { + System.out.println("❌ Avbruten. Låten togs INTE bort."); + } + } + + private void showAllArtists() { + List artists = artistRepo.findAll(); + DisplayHelper.printArtistList(artists); + } + + private void addArtist() { + System.out.print("Artistens namn: "); + String name = scanner.nextLine().trim(); + + if (name.isEmpty()) { + System.out.println("❌ Namn får inte vara tomt."); + return; + } + + Artist artist = new Artist(name); + artistRepo.save(artist); + System.out.println("✅ Artist sparad!"); + } + + private void showArtistAlbums() { + Long artistId = InputValidator.getLongInput(scanner, "Artist ID: "); + List albums = albumRepo.findByArtistId(artistId); + + if (albums.isEmpty()) { + System.out.println("ℹ️ Artist har inga album."); + } else { + DisplayHelper.printAlbumList(albums); + } + } + + private void deleteArtist() { + Long artistId = InputValidator.getLongInput(scanner, "Artist ID att ta bort: "); + + System.out.print("⚠️ Detta tar också bort artistens alla album och låtar. Bekräfta? (JA/nej): "); + String confirm = scanner.nextLine(); + + if (confirm.equalsIgnoreCase("JA")) { + boolean success = artistRepo.deleteArtist(artistId); + System.out.println(success ? "✅ Artist borttagen!" : "❌ Misslyckades"); + } else { + System.out.println("❌ Avbruten."); + } + } + + private void showAllSongs() { + List songs = songRepo.findAll(); + DisplayHelper.printSongList(songs); + } + + private void addSong() { + System.out.print("Låtens titel: "); + String title = scanner.nextLine().trim(); + + if (title.isEmpty()) { + System.out.println("❌ Titel får inte vara tom."); + return; + } + + int duration = InputValidator.getIntInput(scanner, "Längd i sekunder: ", 1, 3600); + Long albumId = InputValidator.getLongInput(scanner, "Album ID: "); + + Album album = albumRepo.findById(albumId); + if (album == null) { + System.out.println("❌ Album hittades inte."); + return; + } + + Song song = new Song(title, duration); + song.setAlbum(album); + songRepo.save(song); + + System.out.println("✅ Låt sparad!"); + } + + private void albumMenu() { + System.out.println("\nAlbum-menyn - implementeras senare"); + } + + private void playlistMenu() { + System.out.println("\nSpellista-menyn - implementeras senare"); + } + + private void searchMenu() { + System.out.println("\nSök-menyn - implementeras senare"); + } +} From 014a2031f631c932328030d07d9aa0b904aed05c Mon Sep 17 00:00:00 2001 From: Johan Date: Wed, 14 Jan 2026 20:27:39 +0100 Subject: [PATCH 7/8] musicdb Co-authored-by: Johan Jansson Co-authored-by: Emma Travljanin --- .gitignore | 58 +- docker-compose.yml | 2 + pom.xml | 16 +- src/main/java/org/example/App.java | 7 - src/main/java/org/example/Main.java | 579 +--------------- src/main/java/org/example/model/Album.java | 87 ++- src/main/java/org/example/model/Artist.java | 1 - src/main/java/org/example/model/Playlist.java | 3 +- .../java/org/example/model/PlaylistSong.java | 27 +- src/main/java/org/example/model/Song.java | 3 +- .../repository/AlbumRepository.java | 32 +- .../repository/ArtistRepository.java | 20 +- .../repository/PlaylistRepository.java | 62 +- .../repository/SongRepository.java | 20 +- .../repository/TransactionHelper.java | 28 +- src/main/java/ui/DisplayHelper.java | 4 +- src/main/java/ui/InputValidator.java | 8 +- src/main/java/ui/MenuManager.java | 652 +++++++++++++++--- .../META-INF/persistence.xml.example | 22 + 19 files changed, 886 insertions(+), 745 deletions(-) delete mode 100644 src/main/java/org/example/App.java create mode 100644 src/main/resources/META-INF/persistence.xml.example diff --git a/.gitignore b/.gitignore index bc9e3cc1..c02e39f3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,56 @@ +# Maven target/ -/.idea/ -src/main/resources/META-INF/persistence.xml -*.db -*.mv.db -*.trace.db +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar + +# IntelliJ IDEA .idea/ *.iml *.iws -target/ +*.ipr +out/ + +# VS Code +.vscode/ + +# OS +.DS_Store +Thumbs.db +desktop.ini + +# Logs +*.log +logs/ + +# Database files +*.db +*.mv.db +*.trace.db + +# Docker override +docker-compose.override.yml + +# Environment files +.env +.env.local +.env.*.local + +# Configuration files - VIKTIGAST! +src/main/resources/META-INF/persistence.xml +src/main/resources/application.properties +src/main/resources/application.yml +src/main/resources/application.yaml + +# Temp files +*.tmp +*.temp +*.bak +*.swp +*~ diff --git a/docker-compose.yml b/docker-compose.yml index f8afb068..820b4893 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,6 +16,8 @@ services: - mysql-data:/var/lib/mysql command: - --default-authentication-plugin=mysql_native_password + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci phpmyadmin: image: phpmyadmin/phpmyadmin diff --git a/pom.xml b/pom.xml index 87a5f80b..a1a166cb 100644 --- a/pom.xml +++ b/pom.xml @@ -1,15 +1,16 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.example JavaJPA 1.0-SNAPSHOT - 17 + 17 + 17 UTF-8 5.6.15.Final 8.0.33 @@ -21,24 +22,15 @@ hibernate-core ${hibernate.version} - javax.persistence javax.persistence-api 2.2 - mysql mysql-connector-java ${mysql.version} - - - org.junit.jupiter - junit-jupiter - 5.10.0 - test - diff --git a/src/main/java/org/example/App.java b/src/main/java/org/example/App.java deleted file mode 100644 index 165e5cd5..00000000 --- a/src/main/java/org/example/App.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.example; - -public class App { - public static void main(String[] args) { - System.out.println("Hello There!"); - } -} diff --git a/src/main/java/org/example/Main.java b/src/main/java/org/example/Main.java index 8afb9381..4078015c 100644 --- a/src/main/java/org/example/Main.java +++ b/src/main/java/org/example/Main.java @@ -1,569 +1,50 @@ package org.example; -import persistence.repository.*; -import org.example.model.*; +import persistence.repository.ArtistRepository; +import persistence.repository.AlbumRepository; +import persistence.repository.SongRepository; +import persistence.repository.PlaylistRepository; +import org.example.ui.MenuManager; import javax.persistence.*; -import java.util.List; import java.util.Scanner; public class Main { - static EntityManager em; - static Scanner scan = new Scanner(System.in); - - static ArtistRepository artistRepo; - static AlbumRepository albumRepo; - static SongRepository songRepo; - static PlaylistRepository playlistRepo; - static TransactionHelper transactionHelper; - public static void main(String[] args) { - EntityManagerFactory emf = Persistence.createEntityManagerFactory("musicPU"); - em = emf.createEntityManager(); - - artistRepo = new ArtistRepository(em); - albumRepo = new AlbumRepository(em); - songRepo = new SongRepository(em); - playlistRepo = new PlaylistRepository(em); - transactionHelper = new TransactionHelper(em); - - System.out.println(" VÄLKOMMEN TILL MUSIKAPPEN "); - - boolean running = true; - while(running) { - System.out.println("\n=== HUVUDMENY ==="); - System.out.println("1. Lägg till artist"); - System.out.println("2. Visa alla artister"); - System.out.println("3. Lägg till album"); - System.out.println("4. Visa albums för artist"); - System.out.println("5. Lägg till låt"); - System.out.println("6. Visa låtar för album"); - System.out.println("7. Visa all musik"); - System.out.println("8. Skapa spellista"); - System.out.println("9. Visa alla spellistor"); - System.out.println("10. Lägg till låt i spellista"); - System.out.println("11. Ta bort låt från spellista"); - System.out.println("0. Avsluta"); - System.out.print("Välj: "); - - int val = 0; - try { - val = scan.nextInt(); - } catch (Exception e) { - System.out.println("Ogiltigt val!"); - scan.nextLine(); - continue; - } - scan.nextLine(); - - switch(val) { - case 1: addArtist(); break; - case 2: showArtists(); break; - case 3: addAlbum(); break; - case 4: showAlbumsByArtist(); break; - case 5: addSong(); break; - case 6: showSongsByAlbum(); break; - case 7: showAllMusic(); break; - case 8: createPlaylist(); break; - case 9: showPlaylists(); break; - case 10: addSongToPlaylist(); break; - case 11: removeSongFromPlaylist(); break; - case 0: - running = false; - System.out.println(" Hej då!"); - break; - default: - System.out.println(" Ogiltigt val!"); - } - } - - em.close(); - emf.close(); - scan.close(); - } - - static void addArtist() { - System.out.print("Artist namn: "); - String name = scan.nextLine(); - - if (name.trim().isEmpty()) { - System.out.println("Namn får inte vara tomt!"); - return; - } - - transactionHelper.executeInTransaction(() -> { - Artist artist = new Artist(name); - artistRepo.save(artist); - System.out.println(" Artist tillagd med ID: " + artist.getId()); - }); - } - - static void showArtists() { - List artists = artistRepo.findAll(); - - System.out.println("\n=== ALLA ARTISTER ==="); - if (artists.isEmpty()) { - System.out.println("Inga artister finns."); - return; - } - - for(Artist a : artists) { - System.out.println(a.getId() + ". " + a.getName() + - " (" + a.getAlbums().size() + " album)"); - } - } - - static void addAlbum() { - List artists = artistRepo.findAll(); - - if(artists.isEmpty()) { - System.out.println(" Inga artister finns. Lägg till artist först."); - return; - } - - System.out.println("\n--- Välj artist ---"); - for(int i = 0; i < artists.size(); i++) { - System.out.println(i + ". " + artists.get(i).getName()); - } - System.out.print("Välj artist (nummer): "); - - int artistIndex = -1; - try { - artistIndex = scan.nextInt(); - } catch (Exception e) { - System.out.println("Ogiltigt val!"); - scan.nextLine(); - return; - } - scan.nextLine(); - - if(artistIndex < 0 || artistIndex >= artists.size()) { - System.out.println(" Ogiltigt val!"); - return; - } - - Artist selectedArtist = artists.get(artistIndex); - - System.out.print("Album titel: "); - String title = scan.nextLine(); - System.out.print("Utgivningsår: "); - - int year = 0; - try { - year = scan.nextInt(); - } catch (Exception e) { - System.out.println("Ogiltigt år!"); - scan.nextLine(); - return; - } - scan.nextLine(); - - if (year < 1900 || year > 2100) { - System.out.println("Ogiltigt år! Måste vara mellan 1900-2100."); - return; - } - - final Artist finalArtist = selectedArtist; - final String finalTitle = title; - final int finalYear = year; - - transactionHelper.executeInTransaction(() -> { - Album album = new Album(finalTitle, finalYear); - album.setArtist(finalArtist); - albumRepo.save(album); - System.out.println(" Album tillagt med ID: " + album.getId()); - }); - } - - static void showAlbumsByArtist() { - System.out.print("Artist ID (tryck 0 för att se alla artister): "); - - Long artistId = 0L; - try { - artistId = scan.nextLong(); - } catch (Exception e) { - System.out.println("Ogiltigt ID!"); - scan.nextLine(); - return; - } - scan.nextLine(); - - if (artistId == 0) { - showArtists(); - return; - } - - Artist artist = artistRepo.findById(artistId); - if (artist == null) { - System.out.println("Artist med ID " + artistId + " finns inte."); - return; - } - - List albums = albumRepo.findByArtistId(artistId); - System.out.println("\n=== ALBUMS AV " + artist.getName() + " ==="); - - if (albums.isEmpty()) { - System.out.println("Inga album för denna artist."); - return; - } - - for(Album a : albums) { - System.out.println(a.getId() + ". " + a.getTitle() + - " (" + a.getYear() + ") - " + a.getSongs().size() + " låtar"); - } - } - - static void addSong() { - List albums = albumRepo.findAll(); - - if(albums.isEmpty()) { - System.out.println(" Inga album finns. Lägg till album först."); - return; - } - - System.out.println("\n--- Välj album ---"); - for(int i = 0; i < albums.size(); i++) { - Album a = albums.get(i); - System.out.println(i + ". " + a.getTitle() + " - " + - a.getArtist().getName() + " (" + a.getYear() + ")"); - } - System.out.print("Välj album (nummer): "); - - int albumIndex = -1; - try { - albumIndex = scan.nextInt(); - } catch (Exception e) { - System.out.println("Ogiltigt val!"); - scan.nextLine(); - return; - } - scan.nextLine(); - - if(albumIndex < 0 || albumIndex >= albums.size()) { - System.out.println(" Ogiltigt val!"); - return; - } - - Album selectedAlbum = albums.get(albumIndex); - - System.out.print("Låt titel: "); - String title = scan.nextLine(); - System.out.print("Längd i sekunder: "); - - int duration = 0; - try { - duration = scan.nextInt(); - } catch (Exception e) { - System.out.println("Ogiltig längd!"); - scan.nextLine(); - return; - } - scan.nextLine(); - - if (duration <= 0) { - System.out.println("Längden måste vara större än 0."); - return; - } - - final Album finalAlbum = selectedAlbum; - final String finalTitle = title; - final int finalDuration = duration; - - transactionHelper.executeInTransaction(() -> { - Song song = new Song(finalTitle, finalDuration); - song.setAlbum(finalAlbum); - songRepo.save(song); - System.out.println(" Låt tillagd med ID: " + song.getId()); - }); - } - - static void showSongsByAlbum() { - System.out.print("Album ID (tryck 0 för att se alla album): "); - - Long albumId = 0L; - try { - albumId = scan.nextLong(); - } catch (Exception e) { - System.out.println("Ogiltigt ID!"); - scan.nextLine(); - return; - } - scan.nextLine(); + System.out.println("🎵 Startar Musikappen..."); - if (albumId == 0) { - showAllAlbums(); - return; - } - - Album album = albumRepo.findById(albumId); - if (album == null) { - System.out.println("Album med ID " + albumId + " finns inte."); - return; - } - - List songs = songRepo.findByAlbumId(albumId); - System.out.println("\n=== LÅTAR PÅ \"" + album.getTitle() + "\" ==="); - - if (songs.isEmpty()) { - System.out.println("Inga låtar på detta album."); - return; - } - - for(Song s : songs) { - int minutes = s.getDuration() / 60; - int seconds = s.getDuration() % 60; - System.out.println(s.getId() + ". " + s.getTitle() + - " (" + minutes + ":" + String.format("%02d", seconds) + ")"); - } - } - - static void showAllAlbums() { - List albums = albumRepo.findAll(); - - System.out.println("\n=== ALLA ALBUM ==="); - if (albums.isEmpty()) { - System.out.println("Inga album finns."); - return; - } - - for(Album a : albums) { - System.out.println(a.getId() + ". " + a.getTitle() + - " - " + a.getArtist().getName() + - " (" + a.getYear() + ") - " + a.getSongs().size() + " låtar"); - } - } - - static void showAllMusic() { - List artists = artistRepo.findAll(); - - System.out.println("\n=== HELA MUSIKBIBLIOTEKET ==="); - - if(artists.isEmpty()) { - System.out.println("Ingen musik finns ännu."); - return; - } - - for(Artist artist : artists) { - System.out.println("\n ARTIST: " + artist.getName()); - - if(artist.getAlbums().isEmpty()) { - System.out.println(" (Inga album)"); - continue; - } - - for(Album album : artist.getAlbums()) { - System.out.println(" ALBUM: " + album.getTitle() + " (" + album.getYear() + ")"); - - if(album.getSongs().isEmpty()) { - System.out.println(" (Inga låtar)"); - continue; - } - - for(Song song : album.getSongs()) { - int minutes = song.getDuration() / 60; - int seconds = song.getDuration() % 60; - System.out.println(" 🎶 " + song.getTitle() + - " (" + minutes + ":" + String.format("%02d", seconds) + ")"); - } - } - } - System.out.println("=============================="); - } - - static void createPlaylist() { - System.out.print("Spellista namn: "); - String name = scan.nextLine(); - - if (name.trim().isEmpty()) { - System.out.println("Namn får inte vara tomt!"); - return; - } - - final String finalName = name; - - transactionHelper.executeInTransaction(() -> { - Playlist playlist = playlistRepo.createPlaylist(finalName); - System.out.println(" Spellista skapad med ID: " + playlist.getId()); - }); - } - - static void showPlaylists() { - List playlists = playlistRepo.findAll(); - - System.out.println("\n=== ALLA SPELLISTOR ==="); - if (playlists.isEmpty()) { - System.out.println("Inga spellistor finns."); - return; - } - - for(Playlist p : playlists) { - System.out.println(p.getId() + ". " + p.getName() + - " (skapad: " + p.getCreatedAt() + ") - " + - p.getEntries().size() + " låtar"); - } - } - - static void addSongToPlaylist() { - List playlists = playlistRepo.findAll(); - List songs = songRepo.findAll(); - - if (playlists.isEmpty()) { - System.out.println("Inga spellistor finns. Skapa en först."); - return; - } - - if (songs.isEmpty()) { - System.out.println("Inga låtar finns. Lägg till låtar först."); - return; - } - - System.out.println("\n--- Välj spellista ---"); - for(int i = 0; i < playlists.size(); i++) { - Playlist p = playlists.get(i); - System.out.println(i + ". " + p.getName() + - " (" + p.getEntries().size() + " låtar)"); - } - System.out.print("Välj spellista (nummer): "); - - int playlistIndex = -1; try { - playlistIndex = scan.nextInt(); - } catch (Exception e) { - System.out.println("Ogiltigt val!"); - scan.nextLine(); - return; - } - scan.nextLine(); - - if (playlistIndex < 0 || playlistIndex >= playlists.size()) { - System.out.println("Ogiltigt val!"); - return; - } - - Playlist playlist = playlists.get(playlistIndex); - - System.out.println("\n--- Välj låt ---"); - for(int i = 0; i < songs.size(); i++) { - Song s = songs.get(i); - System.out.println(i + ". " + s.getTitle() + - " - " + s.getAlbum().getArtist().getName() + - " (" + s.getAlbum().getTitle() + ")"); - } - System.out.print("Välj låt (nummer): "); - - int songIndex = -1; - try { - songIndex = scan.nextInt(); - } catch (Exception e) { - System.out.println("Ogiltigt val!"); - scan.nextLine(); - return; - } - scan.nextLine(); - - if (songIndex < 0 || songIndex >= songs.size()) { - System.out.println("Ogiltigt val!"); - return; - } - - Song song = songs.get(songIndex); - System.out.print("Position i spellistan: "); - - int position = 1; - try { - position = scan.nextInt(); - } catch (Exception e) { - System.out.println("Ogiltig position!"); - scan.nextLine(); - return; - } - scan.nextLine(); + // Skapa EntityManagerFactory + EntityManagerFactory emf = Persistence.createEntityManagerFactory("musicPU"); + System.out.println("✅ Ansluten till databasen"); - if (position < 1) { - System.out.println("Position måste vara minst 1."); - return; - } + // Skapa EntityManager + EntityManager em = emf.createEntityManager(); - final Long finalPlaylistId = playlist.getId(); - final Long finalSongId = song.getId(); - final int finalPosition = position; + // Skapa Scanner för användarinput + Scanner scanner = new Scanner(System.in); - transactionHelper.executeInTransaction(() -> { - playlistRepo.addSong(finalPlaylistId, finalSongId, finalPosition); - System.out.println(" Låt tillagd i spellistan!"); - }); - } + // Skapa alla repositories + System.out.println("🔄 Skapar repositories..."); + ArtistRepository artistRepo = new ArtistRepository(em); + AlbumRepository albumRepo = new AlbumRepository(em); + SongRepository songRepo = new SongRepository(em); + PlaylistRepository playlistRepo = new PlaylistRepository(em); - static void removeSongFromPlaylist() { - List playlists = playlistRepo.findAll(); + // Skapa MenuManager och starta huvudmenyn + MenuManager menuManager = new MenuManager(scanner, artistRepo, albumRepo, songRepo, playlistRepo); - if (playlists.isEmpty()) { - System.out.println("Inga spellistor finns."); - return; - } + // Starta applikationen + menuManager.start(); - System.out.println("\n--- Välj spellista ---"); - for(int i = 0; i < playlists.size(); i++) { - Playlist p = playlists.get(i); - System.out.println(i + ". " + p.getName() + - " (" + p.getEntries().size() + " låtar)"); - } - System.out.print("Välj spellista (nummer): "); + // Stäng alla resurser + System.out.println("👋 Stänger applikationen..."); + scanner.close(); + em.close(); + emf.close(); - int playlistIndex = -1; - try { - playlistIndex = scan.nextInt(); } catch (Exception e) { - System.out.println("Ogiltigt val!"); - scan.nextLine(); - return; + System.err.println("❌ Ett fel uppstod vid start: " + e.getMessage()); + e.printStackTrace(); } - scan.nextLine(); - - if (playlistIndex < 0 || playlistIndex >= playlists.size()) { - System.out.println("Ogiltigt val!"); - return; - } - - Playlist playlist = playlists.get(playlistIndex); - - if (playlist.getEntries().isEmpty()) { - System.out.println("Spellistan är tom."); - return; - } - - System.out.println("\n--- Välj låt att ta bort ---"); - List entries = playlist.getEntries(); - for(int i = 0; i < entries.size(); i++) { - PlaylistSong entry = entries.get(i); - Song song = entry.getSong(); - System.out.println(i + ". " + song.getTitle() + - " (position: " + entry.getPosition() + ")"); - } - System.out.print("Välj låt (nummer): "); - - int songIndex = -1; - try { - songIndex = scan.nextInt(); - } catch (Exception e) { - System.out.println("Ogiltigt val!"); - scan.nextLine(); - return; - } - scan.nextLine(); - - if (songIndex < 0 || songIndex >= entries.size()) { - System.out.println("Ogiltigt val!"); - return; - } - - PlaylistSong entry = entries.get(songIndex); - - final Long finalPlaylistId = playlist.getId(); - final Long finalSongId = entry.getSong().getId(); - - transactionHelper.executeInTransaction(() -> { - playlistRepo.removeSong(finalPlaylistId, finalSongId); - System.out.println(" Låt borttagen från spellistan!"); - }); } } diff --git a/src/main/java/org/example/model/Album.java b/src/main/java/org/example/model/Album.java index 8955ea29..8b130b0d 100644 --- a/src/main/java/org/example/model/Album.java +++ b/src/main/java/org/example/model/Album.java @@ -5,12 +5,15 @@ import java.util.List; @Entity +@Table(name = "album") public class Album { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; + + @Column(name = "release_year") private int releaseYear; @ManyToOne @@ -20,26 +23,82 @@ public class Album { @OneToMany(mappedBy = "album", cascade = CascadeType.ALL, orphanRemoval = true) private List songs = new ArrayList<>(); - public Album() {} + // Konstruktorer + public Album() { + } - public Album(String title, int year) { + public Album(String title, int releaseYear) { this.title = title; - this.releaseYear = year; + this.releaseYear = releaseYear; + } + + public Album(String title, int releaseYear, Artist artist) { + this.title = title; + this.releaseYear = releaseYear; + this.artist = artist; + } + + // Getters och Setters + public Long getId() { + return id; } - // Get & Set - public Long getId() { return id; } - public void setId(Long id) { this.id = id; } + public void setId(Long id) { + this.id = id; + } - public String getTitle() { return title; } - public void setTitle(String title) { this.title = title; } + public String getTitle() { + return title; + } - public int getYear() { return releaseYear; } - public void setYear(int year) { this.releaseYear = year; } + public void setTitle(String title) { + this.title = title; + } - public Artist getArtist() { return artist; } - public void setArtist(Artist artist) { this.artist = artist; } + public int getReleaseYear() { + return releaseYear; + } + + public void setReleaseYear(int releaseYear) { + this.releaseYear = releaseYear; + } - public List getSongs() { return songs; } - public void setSongs(List songs) { this.songs = songs; } + public Artist getArtist() { + return artist; + } + + public void setArtist(Artist artist) { + this.artist = artist; + } + + public List getSongs() { + return songs; + } + + public void setSongs(List songs) { + this.songs = songs; + } + + // Hjälpmetod för att lägga till låt + public void addSong(Song song) { + songs.add(song); + song.setAlbum(this); + } + + // Hjälpmetod för att ta bort låt + public void removeSong(Song song) { + songs.remove(song); + song.setAlbum(null); + } + + @Override + public String toString() { + return "Album{" + + "id=" + id + + ", title='" + title + '\'' + + ", releaseYear=" + releaseYear + + ", artist=" + (artist != null ? artist.getName() : "null") + + ", songs=" + songs.size() + + '}'; + } } diff --git a/src/main/java/org/example/model/Artist.java b/src/main/java/org/example/model/Artist.java index 40d98412..84912793 100644 --- a/src/main/java/org/example/model/Artist.java +++ b/src/main/java/org/example/model/Artist.java @@ -21,7 +21,6 @@ public Artist(String name) { this.name = name; } - // Get & Set public Long getId() { return id; } public void setId(Long id) { this.id = id; } diff --git a/src/main/java/org/example/model/Playlist.java b/src/main/java/org/example/model/Playlist.java index 088bf562..18cc5076 100644 --- a/src/main/java/org/example/model/Playlist.java +++ b/src/main/java/org/example/model/Playlist.java @@ -32,10 +32,9 @@ public void addSong(Song song, int position) { } public void removeSongBySongId(Long songId) { - entries.removeIf(entry -> entry.getSong() != null && songId.equals(entry.getSong().getId())); + entries.removeIf(entry -> songId.equals(entry.getSong().getId())); } - // Getters and Setters public Long getId() { return id; } public String getName() { return name; } public LocalDateTime getCreatedAt() { return createdAt; } diff --git a/src/main/java/org/example/model/PlaylistSong.java b/src/main/java/org/example/model/PlaylistSong.java index 36b74fcc..8d2301c8 100644 --- a/src/main/java/org/example/model/PlaylistSong.java +++ b/src/main/java/org/example/model/PlaylistSong.java @@ -11,9 +11,11 @@ public class PlaylistSong { private Long id; @ManyToOne(optional = false, fetch = FetchType.LAZY) + @JoinColumn(name = "playlist_id", nullable = false) private Playlist playlist; @ManyToOne(optional = false, fetch = FetchType.LAZY) + @JoinColumn(name = "song_id", nullable = false) private Song song; private int position; @@ -27,25 +29,10 @@ public PlaylistSong(Playlist playlist, Song song, int position) { this.position = position; this.addedAt = LocalDateTime.now(); } - // Getters and Setters - public Long getId() { - return id; - } - - public Playlist getPlaylist() { - return playlist; - } - - public Song getSong() { - return song; - } - - public int getPosition() { - return position; - } - - public LocalDateTime getAddedAt() { - return addedAt; - } + public Long getId() { return id; } + public Playlist getPlaylist() { return playlist; } + public Song getSong() { return song; } + public int getPosition() { return position; } + public LocalDateTime getAddedAt() { return addedAt; } } diff --git a/src/main/java/org/example/model/Song.java b/src/main/java/org/example/model/Song.java index 40230f69..8272e06b 100644 --- a/src/main/java/org/example/model/Song.java +++ b/src/main/java/org/example/model/Song.java @@ -9,7 +9,7 @@ public class Song { private Long id; private String title; - private int duration; // i sekunder + private int duration; @ManyToOne @JoinColumn(name = "album_id") @@ -22,7 +22,6 @@ public Song(String title, int duration) { this.duration = duration; } - // Get & Set public Long getId() { return id; } public void setId(Long id) { this.id = id; } diff --git a/src/main/java/persistence/repository/AlbumRepository.java b/src/main/java/persistence/repository/AlbumRepository.java index 14265b5f..a015dff3 100644 --- a/src/main/java/persistence/repository/AlbumRepository.java +++ b/src/main/java/persistence/repository/AlbumRepository.java @@ -1,8 +1,8 @@ package persistence.repository; import org.example.model.Album; -import org.example.model.Artist; import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; import java.util.List; public class AlbumRepository { @@ -13,8 +13,16 @@ public AlbumRepository(EntityManager em) { } public Album save(Album album) { - em.persist(album); - return album; + EntityTransaction transaction = em.getTransaction(); + try { + transaction.begin(); + em.persist(album); + transaction.commit(); + return album; + } catch (Exception e) { + if (transaction.isActive()) transaction.rollback(); + throw e; + } } public Album findById(Long id) { @@ -30,4 +38,22 @@ public List findByArtistId(Long artistId) { .setParameter("artistId", artistId) .getResultList(); } + + public boolean deleteAlbum(Long id) { + EntityTransaction transaction = em.getTransaction(); + try { + transaction.begin(); + Album album = em.find(Album.class, id); + if (album != null) { + em.remove(album); + transaction.commit(); + return true; + } + transaction.rollback(); + return false; + } catch (Exception e) { + if (transaction.isActive()) transaction.rollback(); + return false; + } + } } diff --git a/src/main/java/persistence/repository/ArtistRepository.java b/src/main/java/persistence/repository/ArtistRepository.java index 4f40ac8e..943be7cd 100644 --- a/src/main/java/persistence/repository/ArtistRepository.java +++ b/src/main/java/persistence/repository/ArtistRepository.java @@ -2,6 +2,7 @@ import org.example.model.Artist; import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; import java.util.List; public class ArtistRepository { @@ -12,8 +13,16 @@ public ArtistRepository(EntityManager em) { } public Artist save(Artist artist) { - em.persist(artist); - return artist; + EntityTransaction transaction = em.getTransaction(); + try { + transaction.begin(); + em.persist(artist); + transaction.commit(); + return artist; + } catch (Exception e) { + if (transaction.isActive()) transaction.rollback(); + throw e; + } } public Artist findById(Long id) { @@ -25,14 +34,19 @@ public List findAll() { } public boolean deleteArtist(Long id) { + EntityTransaction transaction = em.getTransaction(); try { - Artist artist = findById(id); + transaction.begin(); + Artist artist = em.find(Artist.class, id); if (artist != null) { em.remove(artist); + transaction.commit(); return true; } + transaction.rollback(); return false; } catch (Exception e) { + if (transaction.isActive()) transaction.rollback(); return false; } } diff --git a/src/main/java/persistence/repository/PlaylistRepository.java b/src/main/java/persistence/repository/PlaylistRepository.java index c377bb29..36fd3821 100644 --- a/src/main/java/persistence/repository/PlaylistRepository.java +++ b/src/main/java/persistence/repository/PlaylistRepository.java @@ -2,7 +2,9 @@ import org.example.model.Playlist; import org.example.model.Song; +import org.example.model.PlaylistSong; import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; import java.util.List; public class PlaylistRepository { @@ -13,9 +15,17 @@ public PlaylistRepository(EntityManager em) { } public Playlist createPlaylist(String name) { - Playlist p = new Playlist(name); - em.persist(p); - return p; + EntityTransaction transaction = em.getTransaction(); + try { + transaction.begin(); + Playlist p = new Playlist(name); + em.persist(p); + transaction.commit(); + return p; + } catch (Exception e) { + if (transaction.isActive()) transaction.rollback(); + throw e; + } } public List findAll() { @@ -24,19 +34,49 @@ public List findAll() { } public void addSong(Long playlistId, Long songId, int position) { - Playlist playlist = em.find(Playlist.class, playlistId); - if (playlist == null) throw new IllegalArgumentException("Playlist not found."); + EntityTransaction transaction = em.getTransaction(); + try { + transaction.begin(); + Playlist playlist = em.find(Playlist.class, playlistId); + if (playlist == null) throw new IllegalArgumentException("Playlist not found."); - Song song = em.find(Song.class, songId); - if (song == null) throw new IllegalArgumentException("Song not found."); + Song song = em.find(Song.class, songId); + if (song == null) throw new IllegalArgumentException("Song not found."); - playlist.addSong(song, position); + PlaylistSong entry = new PlaylistSong(playlist, song, position); + em.persist(entry); + transaction.commit(); + } catch (Exception e) { + if (transaction.isActive()) transaction.rollback(); + throw e; + } } public void removeSong(Long playlistId, Long songId) { - Playlist playlist = em.find(Playlist.class, playlistId); - if (playlist == null) throw new IllegalArgumentException("Playlist not found."); + EntityTransaction transaction = em.getTransaction(); + try { + transaction.begin(); + Playlist playlist = em.find(Playlist.class, playlistId); + if (playlist == null) throw new IllegalArgumentException("Playlist not found."); - playlist.removeSongBySongId(songId); + // Hitta PlaylistSong-attributet + PlaylistSong entry = em.createQuery( + "SELECT ps FROM PlaylistSong ps WHERE ps.playlist.id = :playlistId AND ps.song.id = :songId", + PlaylistSong.class) + .setParameter("playlistId", playlistId) + .setParameter("songId", songId) + .getResultStream() + .findFirst() + .orElse(null); + + if (entry != null) { + em.remove(entry); + } + + transaction.commit(); + } catch (Exception e) { + if (transaction.isActive()) transaction.rollback(); + throw e; + } } } diff --git a/src/main/java/persistence/repository/SongRepository.java b/src/main/java/persistence/repository/SongRepository.java index d87ed6e5..da9cf57a 100644 --- a/src/main/java/persistence/repository/SongRepository.java +++ b/src/main/java/persistence/repository/SongRepository.java @@ -2,6 +2,7 @@ import org.example.model.Song; import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; import java.util.List; public class SongRepository { @@ -12,8 +13,16 @@ public SongRepository(EntityManager em) { } public Song save(Song song) { - em.persist(song); - return song; + EntityTransaction transaction = em.getTransaction(); + try { + transaction.begin(); + em.persist(song); + transaction.commit(); + return song; + } catch (Exception e) { + if (transaction.isActive()) transaction.rollback(); + throw e; + } } public Song findById(Long id) { @@ -31,14 +40,19 @@ public List findByAlbumId(Long albumId) { } public boolean deleteSong(Long id) { + EntityTransaction transaction = em.getTransaction(); try { - Song song = findById(id); + transaction.begin(); + Song song = em.find(Song.class, id); if (song != null) { em.remove(song); + transaction.commit(); return true; } + transaction.rollback(); return false; } catch (Exception e) { + if (transaction.isActive()) transaction.rollback(); return false; } } diff --git a/src/main/java/persistence/repository/TransactionHelper.java b/src/main/java/persistence/repository/TransactionHelper.java index 20d6882d..74f2579b 100644 --- a/src/main/java/persistence/repository/TransactionHelper.java +++ b/src/main/java/persistence/repository/TransactionHelper.java @@ -9,31 +9,17 @@ public TransactionHelper(EntityManager em) { this.em = em; } - public void beginTransaction() { - if (!em.getTransaction().isActive()) { - em.getTransaction().begin(); - } - } - - public void commitTransaction() { - if (em.getTransaction().isActive()) { - em.getTransaction().commit(); - } - } - - public void rollbackTransaction() { - if (em.getTransaction().isActive()) { - em.getTransaction().rollback(); - } - } - public void executeInTransaction(Runnable operation) { + var transaction = em.getTransaction(); try { - beginTransaction(); + transaction.begin(); operation.run(); - commitTransaction(); + transaction.commit(); } catch (Exception e) { - rollbackTransaction(); + if (transaction.isActive()) { + transaction.rollback(); + } + System.err.println("Transaction failed: " + e.getMessage()); throw e; } } diff --git a/src/main/java/ui/DisplayHelper.java b/src/main/java/ui/DisplayHelper.java index 03b1db5e..1621ba99 100644 --- a/src/main/java/ui/DisplayHelper.java +++ b/src/main/java/ui/DisplayHelper.java @@ -1,4 +1,4 @@ -package org.example.ui; // eller org.example.UI +package org.example.ui; import org.example.model.Artist; import org.example.model.Album; @@ -41,7 +41,7 @@ public static void printAlbumList(List albums) { a.getId(), truncate(a.getTitle(), 23), truncate(a.getArtist().getName(), 18), - a.getYear()); // ÄNDRA HÄR: getYear() istället för getReleaseYear() + a.getReleaseYear()); } } diff --git a/src/main/java/ui/InputValidator.java b/src/main/java/ui/InputValidator.java index c8a759c1..661dcbd6 100644 --- a/src/main/java/ui/InputValidator.java +++ b/src/main/java/ui/InputValidator.java @@ -9,7 +9,7 @@ public static int getIntInput(Scanner scanner, String prompt, int min, int max) System.out.print(prompt); try { int value = scanner.nextInt(); - scanner.nextLine(); // Rensa newline + scanner.nextLine(); if (value >= min && value <= max) { return value; @@ -18,7 +18,7 @@ public static int getIntInput(Scanner scanner, String prompt, int min, int max) } } catch (Exception e) { System.out.println("❌ Ogiltigt nummer. Försök igen."); - scanner.nextLine(); // Rensa felaktig input + scanner.nextLine(); } } } @@ -28,11 +28,11 @@ public static long getLongInput(Scanner scanner, String prompt) { System.out.print(prompt); try { long value = scanner.nextLong(); - scanner.nextLine(); // Rensa newline + scanner.nextLine(); return value; } catch (Exception e) { System.out.println("❌ Ogiltigt nummer. Försök igen."); - scanner.nextLine(); // Rensa felaktig input + scanner.nextLine(); } } } diff --git a/src/main/java/ui/MenuManager.java b/src/main/java/ui/MenuManager.java index 5b814a1f..ab1bf78f 100644 --- a/src/main/java/ui/MenuManager.java +++ b/src/main/java/ui/MenuManager.java @@ -27,7 +27,7 @@ public MenuManager(Scanner scanner, this.playlistRepo = playlistRepo; } - //HUVUDMETOD + // HUVUDMETOD public void start() { System.out.println("🎵 VÄLKOMMEN TILL MUSIKAPPEN 🎵"); @@ -39,18 +39,16 @@ public void start() { System.out.println("2. 💿 Album"); System.out.println("3. 🎶 Låtar"); System.out.println("4. 📋 Spellistor"); - System.out.println("5. 🔍 Sök"); System.out.println("0. ❌ Avsluta"); System.out.println("=".repeat(40)); - int choice = InputValidator.getIntInput(scanner, "Val: ", 0, 5); + int choice = InputValidator.getIntInput(scanner, "Val: ", 0, 4); switch (choice) { case 1: artistMenu(); break; case 2: albumMenu(); break; case 3: songMenu(); break; case 4: playlistMenu(); break; - case 5: searchMenu(); break; case 0: running = false; System.out.println("\n👋 Tack för idag!"); @@ -59,7 +57,7 @@ public void start() { } } - // ARTIST-MENY + // ========== ARTIST-MENY ========== private void artistMenu() { boolean inMenu = true; while (inMenu) { @@ -82,7 +80,323 @@ private void artistMenu() { } } - // LÅT-MENY (med borttagning) + private void showAllArtists() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("ALLA ARTISTER"); + System.out.println("=".repeat(40)); + + List artists = artistRepo.findAll(); + if (artists.isEmpty()) { + System.out.println("Inga artister finns."); + return; + } + + System.out.printf("%-4s %-30s %-15s%n", "ID", "NAMN", "ANTAL ALBUM"); + System.out.println("-".repeat(50)); + + for (Artist artist : artists) { + System.out.printf("%-4d %-30s %-15d%n", + artist.getId(), + truncate(artist.getName(), 28), + artist.getAlbums().size()); + } + } + + private void addArtist() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("LÄGG TILL NY ARTIST"); + System.out.println("=".repeat(40)); + + String name = InputValidator.getNonEmptyString(scanner, "Artistens namn: "); + + try { + Artist artist = new Artist(name); + artistRepo.save(artist); + System.out.println("✅ Artist sparad med ID: " + artist.getId()); + } catch (Exception e) { + System.out.println("❌ Kunde inte spara artisten: " + e.getMessage()); + } + } + + private void showArtistAlbums() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("VISA ARTISTS ALBUM"); + System.out.println("=".repeat(40)); + + // Visa alla artister först + List artists = artistRepo.findAll(); + if (artists.isEmpty()) { + System.out.println("Inga artister finns."); + return; + } + + System.out.println("\n--- Tillgängliga artister ---"); + for (Artist artist : artists) { + System.out.println(artist.getId() + ". " + artist.getName() + + " (" + artist.getAlbums().size() + " album)"); + } + + Long artistId = InputValidator.getLongInput(scanner, "\nAnge Artist ID: "); + Artist artist = artistRepo.findById(artistId); + + if (artist == null) { + System.out.println("❌ Artist hittades inte."); + return; + } + + List albums = albumRepo.findByArtistId(artistId); + + System.out.println("\n" + "=".repeat(50)); + System.out.println("ALBUM AV: " + artist.getName().toUpperCase()); + System.out.println("=".repeat(50)); + + if (albums.isEmpty()) { + System.out.println("Denna artist har inga album än."); + } else { + System.out.printf("%-4s %-30s %-10s%n", "ID", "ALBUM", "ÅR"); + System.out.println("-".repeat(50)); + + for (Album album : albums) { + System.out.printf("%-4d %-30s %-10d%n", + album.getId(), + truncate(album.getTitle(), 28), + album.getReleaseYear()); + } + } + } + + private void deleteArtist() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("TA BORT ARTIST"); + System.out.println("=".repeat(40)); + + Long artistId = InputValidator.getLongInput(scanner, "Artist ID att ta bort: "); + Artist artist = artistRepo.findById(artistId); + + if (artist == null) { + System.out.println("❌ Artist hittades inte."); + return; + } + + System.out.println("\n⚠️ VARNING: Detta tar också bort artistens alla album och låtar!"); + System.out.println("Artist att ta bort: " + artist.getName()); + System.out.println("Antal album: " + artist.getAlbums().size()); + + System.out.print("\nÄr du SÄKER på att du vill ta bort denna artist? (skriv 'JA' för att bekräfta): "); + String confirm = scanner.nextLine().trim(); + + if (confirm.equalsIgnoreCase("JA")) { + boolean success = artistRepo.deleteArtist(artistId); + System.out.println(success ? "✅ Artist borttagen!" : "❌ Misslyckades att ta bort artisten."); + } else { + System.out.println("❌ Avbruten. Ingen artist togs bort."); + } + } + + // ========== ALBUM-MENY ========== + private void albumMenu() { + boolean inMenu = true; + while (inMenu) { + System.out.println("\n=== ALBUM-MENY ==="); + System.out.println("1. Visa alla album"); + System.out.println("2. Lägg till nytt album"); + System.out.println("3. Visa albums låtar"); + System.out.println("4. Ta bort album"); + System.out.println("0. ← Tillbaka till huvudmeny"); + + int choice = InputValidator.getIntInput(scanner, "Val: ", 0, 4); + + switch (choice) { + case 1: showAllAlbums(); break; + case 2: addAlbum(); break; + case 3: showAlbumSongs(); break; + case 4: deleteAlbum(); break; + case 0: inMenu = false; break; + } + } + } + + private void showAllAlbums() { + System.out.println("\n" + "=".repeat(50)); + System.out.println("ALLA ALBUM"); + System.out.println("=".repeat(50)); + + List albums = albumRepo.findAll(); + if (albums.isEmpty()) { + System.out.println("Inga album finns."); + return; + } + + System.out.printf("%-4s %-25s %-20s %-10s%n", "ID", "ALBUM", "ARTIST", "ÅR"); + System.out.println("-".repeat(60)); + + for (Album album : albums) { + String artistName = "Okänd artist"; + if (album.getArtist() != null) { + artistName = album.getArtist().getName(); + } + + System.out.printf("%-4d %-25s %-20s %-10d%n", + album.getId(), + truncate(album.getTitle(), 23), + truncate(artistName, 18), + album.getReleaseYear()); + } + } + + private void addAlbum() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("LÄGG TILL NYTT ALBUM"); + System.out.println("=".repeat(40)); + + // Visa alla artister först + List artists = artistRepo.findAll(); + if (artists.isEmpty()) { + System.out.println("❌ Inga artister finns. Lägg till en artist först."); + return; + } + + System.out.println("\n--- Välj artist ---"); + System.out.printf("%-4s %-30s%n", "ID", "ARTIST"); + System.out.println("-".repeat(35)); + + for (Artist artist : artists) { + System.out.printf("%-4d %-30s%n", + artist.getId(), + truncate(artist.getName(), 28)); + } + + Long artistId = InputValidator.getLongInput(scanner, "\nAnge Artist ID: "); + Artist artist = artistRepo.findById(artistId); + + if (artist == null) { + System.out.println("❌ Artist hittades inte."); + return; + } + + String title = InputValidator.getNonEmptyString(scanner, "Albumets titel: "); + int year = InputValidator.getIntInput(scanner, "Utgivningsår: ", 1900, 2100); + + // Bekräfta + System.out.println("\n" + "=".repeat(40)); + System.out.println("BEKRÄFTA ALBUM"); + System.out.println("=".repeat(40)); + System.out.println("Artist: " + artist.getName()); + System.out.println("Album: " + title); + System.out.println("År: " + year); + + System.out.print("\nVill du spara detta album? (skriv 'JA' för att bekräfta): "); + String confirm = scanner.nextLine().trim(); + + if (!confirm.equalsIgnoreCase("JA")) { + System.out.println("❌ Avbruten. Albumet sparades inte."); + return; + } + + // Skapa och spara album + try { + Album album = new Album(title, year); + album.setArtist(artist); + albumRepo.save(album); + System.out.println("✅ Album sparad med ID: " + album.getId()); + } catch (Exception e) { + System.out.println("❌ Kunde inte spara albumet: " + e.getMessage()); + e.printStackTrace(); + } + } + + private void showAlbumSongs() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("VISA ALBUMS LÅTAR"); + System.out.println("=".repeat(40)); + + // Visa alla album först + List albums = albumRepo.findAll(); + if (albums.isEmpty()) { + System.out.println("Inga album finns."); + return; + } + + System.out.println("\n--- Tillgängliga album ---"); + System.out.printf("%-4s %-25s %-20s%n", "ID", "ALBUM", "ARTIST"); + System.out.println("-".repeat(50)); + + for (Album album : albums) { + String artistName = "Okänd"; + if (album.getArtist() != null) { + artistName = album.getArtist().getName(); + } + + System.out.printf("%-4d %-25s %-20s%n", + album.getId(), + truncate(album.getTitle(), 23), + truncate(artistName, 18)); + } + + Long albumId = InputValidator.getLongInput(scanner, "\nAnge Album ID: "); + Album album = albumRepo.findById(albumId); + + if (album == null) { + System.out.println("❌ Album hittades inte."); + return; + } + + System.out.println("\n" + "=".repeat(50)); + System.out.println("LÅTAR PÅ: " + album.getTitle().toUpperCase()); + if (album.getArtist() != null) { + System.out.println("ARTIST: " + album.getArtist().getName()); + } + System.out.println("ÅR: " + album.getReleaseYear()); + System.out.println("=".repeat(50)); + + List songs = songRepo.findByAlbumId(albumId); + if (songs.isEmpty()) { + System.out.println("Det här albumet har inga låtar än."); + } else { + System.out.printf("%-4s %-30s %-15s%n", "ID", "LÅT", "LÄNGD"); + System.out.println("-".repeat(50)); + + for (Song song : songs) { + System.out.printf("%-4d %-30s %-15s%n", + song.getId(), + truncate(song.getTitle(), 28), + formatDuration(song.getDuration())); + } + } + } + + private void deleteAlbum() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("TA BORT ALBUM"); + System.out.println("=".repeat(40)); + + Long albumId = InputValidator.getLongInput(scanner, "Album ID att ta bort: "); + Album album = albumRepo.findById(albumId); + + if (album == null) { + System.out.println("❌ Album hittades inte."); + return; + } + + System.out.println("\n⚠️ VARNING: Detta tar också bort albumets alla låtar!"); + System.out.println("Album att ta bort: " + album.getTitle()); + if (album.getArtist() != null) { + System.out.println("Artist: " + album.getArtist().getName()); + } + System.out.println("Antal låtar: " + album.getSongs().size()); + + System.out.print("\nÄr du SÄKER på att du vill ta bort detta album? (skriv 'JA' för att bekräfta): "); + String confirm = scanner.nextLine().trim(); + + if (confirm.equalsIgnoreCase("JA")) { + boolean success = albumRepo.deleteAlbum(albumId); + System.out.println(success ? "✅ Album borttaget!" : "❌ Misslyckades att ta bort albumet."); + } else { + System.out.println("❌ Avbruten. Inget album togs bort."); + } + } + + // ========== LÅT-MENY ========== private void songMenu() { boolean inMenu = true; while (inMenu) { @@ -103,7 +417,104 @@ private void songMenu() { } } - // METOD FÖR ATT TA BORT LÅT + private void showAllSongs() { + System.out.println("\n" + "=".repeat(60)); + System.out.println("ALLA LÅTAR"); + System.out.println("=".repeat(60)); + + List songs = songRepo.findAll(); + if (songs.isEmpty()) { + System.out.println("Inga låtar finns."); + return; + } + + System.out.printf("%-4s %-20s %-25s %-15s%n", "ID", "LÅT", "ALBUM", "LÄNGD"); + System.out.println("-".repeat(65)); + + for (Song song : songs) { + String albumTitle = "Okänt album"; + if (song.getAlbum() != null) { + albumTitle = song.getAlbum().getTitle(); + } + + System.out.printf("%-4d %-20s %-25s %-15s%n", + song.getId(), + truncate(song.getTitle(), 18), + truncate(albumTitle, 23), + formatDuration(song.getDuration())); + } + } + + private void addSong() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("LÄGG TILL NY LÅT"); + System.out.println("=".repeat(40)); + + // Visa alla album först + List albums = albumRepo.findAll(); + if (albums.isEmpty()) { + System.out.println("❌ Inga album finns. Lägg till ett album först."); + return; + } + + System.out.println("\n--- Välj album ---"); + System.out.printf("%-4s %-25s %-20s %-10s%n", "ID", "ALBUM", "ARTIST", "ÅR"); + System.out.println("-".repeat(60)); + + for (Album album : albums) { + String artistName = "Okänd"; + if (album.getArtist() != null) { + artistName = album.getArtist().getName(); + } + + System.out.printf("%-4d %-25s %-20s %-10d%n", + album.getId(), + truncate(album.getTitle(), 23), + truncate(artistName, 18), + album.getReleaseYear()); + } + + Long albumId = InputValidator.getLongInput(scanner, "\nAnge Album ID: "); + Album album = albumRepo.findById(albumId); + + if (album == null) { + System.out.println("❌ Album hittades inte."); + return; + } + + String title = InputValidator.getNonEmptyString(scanner, "Låtens titel: "); + int duration = InputValidator.getIntInput(scanner, "Längd i sekunder: ", 1, 3600); + + // Bekräfta + System.out.println("\n" + "=".repeat(40)); + System.out.println("BEKRÄFTA LÅT"); + System.out.println("=".repeat(40)); + System.out.println("Låt: " + title); + System.out.println("Längd: " + formatDuration(duration)); + System.out.println("Album: " + album.getTitle()); + if (album.getArtist() != null) { + System.out.println("Artist: " + album.getArtist().getName()); + } + + System.out.print("\nVill du spara denna låt? (skriv 'JA' för att bekräfta): "); + String confirm = scanner.nextLine().trim(); + + if (!confirm.equalsIgnoreCase("JA")) { + System.out.println("❌ Avbruten. Låten sparades inte."); + return; + } + + // Skapa och spara låten + try { + Song song = new Song(title, duration); + song.setAlbum(album); + songRepo.save(song); + System.out.println("✅ Låt sparad med ID: " + song.getId()); + } catch (Exception e) { + System.out.println("❌ Kunde inte spara låten: " + e.getMessage()); + } + } + private void deleteSong() { System.out.println("\n" + "=".repeat(40)); System.out.println("TA BORT LÅT"); @@ -115,21 +526,26 @@ private void deleteSong() { return; } - DisplayHelper.printSongList(songs); + System.out.println("\n--- Tillgängliga låtar ---"); + System.out.printf("%-4s %-25s %-20s%n", "ID", "LÅT", "ALBUM"); + System.out.println("-".repeat(50)); - System.out.print("\nAnge ID på låten du vill ta bort: "); - Long songId; - try { - songId = scanner.nextLong(); - scanner.nextLine(); - } catch (Exception e) { - System.out.println("❌ Ogiltigt ID. Ange ett nummer."); - scanner.nextLine(); - return; + for (Song song : songs) { + String albumTitle = "Okänt album"; + if (song.getAlbum() != null) { + albumTitle = song.getAlbum().getTitle(); + } + + System.out.printf("%-4d %-25s %-20s%n", + song.getId(), + truncate(song.getTitle(), 23), + truncate(albumTitle, 18)); } - Song songToDelete = songRepo.findById(songId); - if (songToDelete == null) { + Long songId = InputValidator.getLongInput(scanner, "\nAnge ID på låten du vill ta bort: "); + Song song = songRepo.findById(songId); + + if (song == null) { System.out.println("❌ Ingen låt hittades med ID: " + songId); return; } @@ -137,109 +553,175 @@ private void deleteSong() { System.out.println("\n" + "=".repeat(40)); System.out.println("BEKRÄFTA BORTTAGNING"); System.out.println("=".repeat(40)); - System.out.println("Låt: " + songToDelete.getTitle()); - System.out.println("Artist: " + songToDelete.getAlbum().getArtist().getName()); - System.out.println("Album: " + songToDelete.getAlbum().getTitle()); - System.out.println("Längd: " + DisplayHelper.formatDuration(songToDelete.getDuration())); + System.out.println("Låt att ta bort: " + song.getTitle()); + System.out.println("Längd: " + formatDuration(song.getDuration())); - System.out.print("\n⚠️ Är du SÄKER på att du vill ta bort denna låt? (JA/nej): "); - String confirmation = scanner.nextLine().trim(); + if (song.getAlbum() != null) { + System.out.println("Album: " + song.getAlbum().getTitle()); + if (song.getAlbum().getArtist() != null) { + System.out.println("Artist: " + song.getAlbum().getArtist().getName()); + } + } + + System.out.print("\n⚠️ Är du SÄKER på att du vill ta bort denna låt? (skriv 'JA' för att bekräfta): "); + String confirm = scanner.nextLine().trim(); - if (confirmation.equalsIgnoreCase("JA")) { + if (confirm.equalsIgnoreCase("JA")) { boolean success = songRepo.deleteSong(songId); - if (success) { - System.out.println("✅ Låt togs bort!"); - } else { - System.out.println("❌ Kunde inte ta bort låten."); - } + System.out.println(success ? "✅ Låt borttagen!" : "❌ Kunde inte ta bort låten."); } else { System.out.println("❌ Avbruten. Låten togs INTE bort."); } } - private void showAllArtists() { - List artists = artistRepo.findAll(); - DisplayHelper.printArtistList(artists); + // ========== SPELLISTA-MENY ========== + private void playlistMenu() { + boolean inMenu = true; + while (inMenu) { + System.out.println("\n=== SPELLISTA-MENY ==="); + System.out.println("1. Visa alla spellistor"); + System.out.println("2. Skapa ny spellista"); + System.out.println("3. Lägg till låt i spellista"); + System.out.println("4. Ta bort låt från spellista"); + System.out.println("5. Visa spellista"); + System.out.println("6. Ta bort spellista"); + System.out.println("0. ← Tillbaka till huvudmeny"); + + int choice = InputValidator.getIntInput(scanner, "Val: ", 0, 6); + + switch (choice) { + case 1: showAllPlaylists(); break; + case 2: createPlaylist(); break; + case 3: addSongToPlaylist(); break; + case 4: removeSongFromPlaylist(); break; + case 5: showPlaylistDetails(); break; + case 6: deletePlaylist(); break; + case 0: inMenu = false; break; + } + } } - private void addArtist() { - System.out.print("Artistens namn: "); - String name = scanner.nextLine().trim(); + private void showAllPlaylists() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("ALLA SPELLISTOR"); + System.out.println("=".repeat(40)); - if (name.isEmpty()) { - System.out.println("❌ Namn får inte vara tomt."); + List playlists = playlistRepo.findAll(); + if (playlists.isEmpty()) { + System.out.println("Inga spellistor finns."); return; } - Artist artist = new Artist(name); - artistRepo.save(artist); - System.out.println("✅ Artist sparad!"); - } + System.out.printf("%-4s %-25s %-15s%n", "ID", "NAMN", "ANTAL LÅTAR"); + System.out.println("-".repeat(45)); - private void showArtistAlbums() { - Long artistId = InputValidator.getLongInput(scanner, "Artist ID: "); - List albums = albumRepo.findByArtistId(artistId); - - if (albums.isEmpty()) { - System.out.println("ℹ️ Artist har inga album."); - } else { - DisplayHelper.printAlbumList(albums); + for (Playlist playlist : playlists) { + System.out.printf("%-4d %-25s %-15d%n", + playlist.getId(), + truncate(playlist.getName(), 23), + playlist.getEntries().size()); } } - private void deleteArtist() { - Long artistId = InputValidator.getLongInput(scanner, "Artist ID att ta bort: "); + private void createPlaylist() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("SKAPA NY SPELLISTA"); + System.out.println("=".repeat(40)); - System.out.print("⚠️ Detta tar också bort artistens alla album och låtar. Bekräfta? (JA/nej): "); - String confirm = scanner.nextLine(); + String name = InputValidator.getNonEmptyString(scanner, "Spellistans namn: "); - if (confirm.equalsIgnoreCase("JA")) { - boolean success = artistRepo.deleteArtist(artistId); - System.out.println(success ? "✅ Artist borttagen!" : "❌ Misslyckades"); - } else { - System.out.println("❌ Avbruten."); + try { + Playlist playlist = playlistRepo.createPlaylist(name); + System.out.println("✅ Spellista skapad med ID: " + playlist.getId()); + } catch (Exception e) { + System.out.println("❌ Kunde inte skapa spellista: " + e.getMessage()); } } - private void showAllSongs() { - List songs = songRepo.findAll(); - DisplayHelper.printSongList(songs); - } - - private void addSong() { - System.out.print("Låtens titel: "); - String title = scanner.nextLine().trim(); + private void addSongToPlaylist() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("LÄGG TILL LÅT I SPELLISTA"); + System.out.println("=".repeat(40)); - if (title.isEmpty()) { - System.out.println("❌ Titel får inte vara tom."); + // Visa spellistor + List playlists = playlistRepo.findAll(); + if (playlists.isEmpty()) { + System.out.println("❌ Inga spellistor finns. Skapa en först."); return; } - int duration = InputValidator.getIntInput(scanner, "Längd i sekunder: ", 1, 3600); - Long albumId = InputValidator.getLongInput(scanner, "Album ID: "); + System.out.println("\n--- Välj spellista ---"); + for (Playlist playlist : playlists) { + System.out.println(playlist.getId() + ". " + playlist.getName() + + " (" + playlist.getEntries().size() + " låtar)"); + } - Album album = albumRepo.findById(albumId); - if (album == null) { - System.out.println("❌ Album hittades inte."); + Long playlistId = InputValidator.getLongInput(scanner, "\nAnge Spellista ID: "); + + // Visa låtar + List songs = songRepo.findAll(); + if (songs.isEmpty()) { + System.out.println("❌ Inga låtar finns. Lägg till låtar först."); return; } - Song song = new Song(title, duration); - song.setAlbum(album); - songRepo.save(song); + System.out.println("\n--- Välj låt ---"); + for (Song song : songs) { + String albumInfo = ""; + if (song.getAlbum() != null) { + albumInfo = " (Album: " + song.getAlbum().getTitle() + ")"; + } + System.out.println(song.getId() + ". " + song.getTitle() + albumInfo); + } - System.out.println("✅ Låt sparad!"); + Long songId = InputValidator.getLongInput(scanner, "\nAnge Låt ID: "); + int position = InputValidator.getIntInput(scanner, "Position i spellistan: ", 1, 1000); + + try { + playlistRepo.addSong(playlistId, songId, position); + System.out.println("✅ Låt tillagd i spellistan!"); + } catch (Exception e) { + System.out.println("❌ Kunde inte lägga till låt: " + e.getMessage()); + } } - private void albumMenu() { - System.out.println("\nAlbum-menyn - implementeras senare"); + private void removeSongFromPlaylist() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("TA BORT LÅT FRÅN SPELLISTA"); + System.out.println("=".repeat(40)); + + System.out.println("Denna funktion kräver mer avancerad implementation."); + System.out.println("Kommer snart..."); } - private void playlistMenu() { - System.out.println("\nSpellista-menyn - implementeras senare"); + private void showPlaylistDetails() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("VISA SPELLISTA"); + System.out.println("=".repeat(40)); + + System.out.println("Denna funktion kräver mer avancerad implementation."); + System.out.println("Kommer snart..."); + } + + private void deletePlaylist() { + System.out.println("\n" + "=".repeat(40)); + System.out.println("TA BORT SPELLISTA"); + System.out.println("=".repeat(40)); + + System.out.println("Denna funktion kräver mer avancerad implementation."); + System.out.println("Kommer snart..."); + } + + // ========== HJÄLPMETODER ========== + private String truncate(String text, int maxLength) { + if (text == null) return ""; + if (text.length() <= maxLength) return text; + return text.substring(0, maxLength - 3) + "..."; } - private void searchMenu() { - System.out.println("\nSök-menyn - implementeras senare"); + private String formatDuration(int seconds) { + int minutes = seconds / 60; + int remainingSeconds = seconds % 60; + return String.format("%d:%02d", minutes, remainingSeconds); } } diff --git a/src/main/resources/META-INF/persistence.xml.example b/src/main/resources/META-INF/persistence.xml.example new file mode 100644 index 00000000..65644b90 --- /dev/null +++ b/src/main/resources/META-INF/persistence.xml.example @@ -0,0 +1,22 @@ + + + + org.hibernate.jpa.HibernatePersistenceProvider + org.example.model.Artist + org.example.model.Album + org.example.model.Song + org.example.model.Playlist + org.example.model.PlaylistSong + + + + + + + + + + + + From 6b91ab2d652c4a57360096efe42bcae3398b9b4a Mon Sep 17 00:00:00 2001 From: Johan Date: Thu, 15 Jan 2026 02:22:25 +0100 Subject: [PATCH 8/8] flyttade mappstruktur --- src/main/java/{ => org/example}/ui/DisplayHelper.java | 0 src/main/java/{ => org/example}/ui/InputValidator.java | 0 src/main/java/{ => org/example}/ui/MenuManager.java | 0 src/test/java/org/example/AppTest.java | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) rename src/main/java/{ => org/example}/ui/DisplayHelper.java (100%) rename src/main/java/{ => org/example}/ui/InputValidator.java (100%) rename src/main/java/{ => org/example}/ui/MenuManager.java (100%) diff --git a/src/main/java/ui/DisplayHelper.java b/src/main/java/org/example/ui/DisplayHelper.java similarity index 100% rename from src/main/java/ui/DisplayHelper.java rename to src/main/java/org/example/ui/DisplayHelper.java diff --git a/src/main/java/ui/InputValidator.java b/src/main/java/org/example/ui/InputValidator.java similarity index 100% rename from src/main/java/ui/InputValidator.java rename to src/main/java/org/example/ui/InputValidator.java diff --git a/src/main/java/ui/MenuManager.java b/src/main/java/org/example/ui/MenuManager.java similarity index 100% rename from src/main/java/ui/MenuManager.java rename to src/main/java/org/example/ui/MenuManager.java diff --git a/src/test/java/org/example/AppTest.java b/src/test/java/org/example/AppTest.java index d522a7e2..af6a1eac 100644 --- a/src/test/java/org/example/AppTest.java +++ b/src/test/java/org/example/AppTest.java @@ -9,4 +9,4 @@ class AppTest { void test() { assertThat(true).isTrue(); } -} \ No newline at end of file +}