package me.moodcat.database.bootstrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import me.moodcat.database.controllers.ArtistDAO;
import me.moodcat.database.controllers.ChatDAO;
import me.moodcat.database.controllers.RoomDAO;
import me.moodcat.database.controllers.SongDAO;
import me.moodcat.database.controllers.UserDAO;
import me.moodcat.database.embeddables.VAVector;
import me.moodcat.database.entities.Artist;
import me.moodcat.database.entities.ChatMessage;
import me.moodcat.database.entities.Room;
import me.moodcat.database.entities.Song;
import me.moodcat.database.entities.User;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* The {@code Bootstrapper} loads an environment for a test
*
* @author Jan-Willem Gmelig Meyling
*/
@Slf4j
public class Bootstrapper {
private final Map<Integer, Artist> persistedArtists;
private final Map<Integer, Song> persistedSongs;
private final Map<Integer, Room> persistedRooms;
private final Map<Integer, User> persistedUsers;
/**
* ObjectMapper used for the bootstrapper.
*/
private final ObjectMapper objectMapper;
/**
* ArtistDAO.
*/
private final ArtistDAO artistDAO;
private final RoomDAO roomDAO;
private final SongDAO songDAO;
private final ChatDAO chatDAO;
private final UserDAO userDAO;
@Inject
public Bootstrapper(final ObjectMapper objectMapper, final ArtistDAO artistDAO,
final RoomDAO roomDAO, final SongDAO songDAO, final ChatDAO chatDAO,
final UserDAO userDAO) {
this.objectMapper = objectMapper;
this.artistDAO = artistDAO;
this.roomDAO = roomDAO;
this.songDAO = songDAO;
this.chatDAO = chatDAO;
this.userDAO = userDAO;
this.persistedArtists = Maps.newHashMap();
this.persistedSongs = Maps.newHashMap();
this.persistedRooms = Maps.newHashMap();
this.persistedUsers = Maps.newHashMap();
}
/**
* BEnvironment contains the artists and songs to be initialised.
*/
@Data
private static class BEnvironment {
private List<BUser> users;
private List<BArtist> artists;
private List<BRoom> rooms;
}
@Data
private static class BUser {
private int id;
private String username;
private int soundCloudUserId;
private Integer points;
private String accessToken;
}
/**
* BArtist the artist with his songs.
*/
@Data
private static class BArtist {
private int id;
private String name;
private List<BSong> songs;
}
/**
* Song for an artist.
*/
@Data
private static class BSong {
private int id;
private String name;
private String artworkUrl;
private int soundCloudId;
private int duration;
}
@Data
private static class BRoom {
private int id;
private String name;
private int position;
private int time;
private int songId;
private List<Integer> playHistory;
private List<Integer> playQueue;
private List<BMessage> messages;
}
@Data
private static class BMessage {
private Integer id;
private Integer userId;
private String message;
private long time;
}
/**
* Parse environment from resource file.
*
* @param path
* path to resource
* @throws IOException
* if an I/O error occurs
*/
public void parseFromResource(final String path) throws IOException {
try (InputStream in = Bootstrapper.class.getResourceAsStream(path)) {
final BEnvironment environment = objectMapper.readValue(in, BEnvironment.class);
environment.getUsers().forEach(this::createUser);
environment.getArtists().forEach(this::createArtist);
environment.getRooms().forEach(this::createRoom);
}
}
@Transactional
protected void createUser(BUser bUser) {
final User user = new User();
user.setId(bUser.getId());
user.setName(bUser.getUsername());
user.setSoundCloudUserId(bUser.getSoundCloudUserId());
user.setPoints(bUser.getPoints());
user.setAccessToken(bUser.getAccessToken());
User persistedUser = userDAO.merge(user);
persistedUsers.put(persistedUser.getId(), persistedUser);
log.info("Bootstrapper created user {}", persistedUser);
}
@Transactional
protected void createRoom(BRoom bRoom) {
Room room = new Room();
room.setId(bRoom.getId());
room.setName(bRoom.getName());
room.setChatMessages(Collections.emptySet());
room.setCurrentSong(persistedSongs.get(bRoom.getSongId()));
room.setPlayHistory(findSongs(bRoom.getPlayHistory()));
room.setPlayQueue(findSongs(bRoom.getPlayQueue()));
room.setVaVector(room.getCurrentSong().getValenceArousal());
Room persistedRoom = roomDAO.merge(room);
bRoom.getMessages().forEach(bSong -> createChatMessage(bSong, persistedRoom));
persistedRooms.put(bRoom.getId(), persistedRoom);
log.info("Bootstrapper created room {}", persistedRoom);
}
private List<Song> findSongs(final List<Integer> songIds) {
if(songIds == null) {
return Collections.emptyList();
}
else {
return songIds.stream()
.map(persistedSongs::get)
.collect(Collectors.toList());
}
}
@Transactional
protected ChatMessage createChatMessage(BMessage bMessage, Room room) {
ChatMessage chatMessage = new ChatMessage();
chatMessage.setId(bMessage.getId());
chatMessage.setUser(persistedUsers.get(bMessage.getUserId()));
chatMessage.setMessage(bMessage.getMessage());
chatMessage.setTimestamp(bMessage.getTime());
chatMessage.setRoom(room);
return chatDAO.merge(chatMessage);
}
@Transactional
protected Song createSong(BSong bSong, Artist artist) {
Song song = new Song();
song.setId(bSong.getId());
song.setName(bSong.getName());
song.setArtworkUrl(bSong.getArtworkUrl());
song.setDuration(bSong.getDuration());
song.setSoundCloudId(bSong.getSoundCloudId());
song.setArtist(artist);
song.setValenceArousal(VAVector.createRandomVector());
song = songDAO.merge(song);
persistedSongs.put(bSong.getId(), song);
return song;
}
@Transactional
protected void createArtist(BArtist bArtist) {
final Artist artist = new Artist();
artist.setId(bArtist.getId());
artist.setName(bArtist.getName());
Artist persistedArtist = artistDAO.merge(artist);
persistedArtists.put(bArtist.getId(), persistedArtist);
bArtist.getSongs().forEach(bSong -> createSong(bSong, persistedArtist));
log.info("Bootstrapper created artist {}", persistedArtist);
}
/**
* Remove persisted entitites from the database.
*/
public void cleanup() {
persistedArtists.clear();
persistedSongs.clear();
persistedRooms.clear();
}
/**
* Get a persisted artist
*
* @param id
* id for the artist
* @return artist
*/
public Artist getArtist(Integer id) {
return persistedArtists.get(id);
}
/**
* Get a persisted Room
*
* @param id
* id for the Room
* @return Room
*/
public Room getRoom(Integer id) {
return persistedRooms.get(id);
}
/**
* Get an artist
*
* @param id
* id for the Song
* @return an artist
*/
public Song getSong(Integer id) {
return persistedSongs.get(id);
}
public User getUser(Integer id) {
return persistedUsers.get(id);
}
}