This repository has been archived on 2021-08-17. You can view files and clone it, but cannot push or open issues or pull requests.
wendys-racing-horses/backend/src/main/java/at/ac/tuwien/sepm/assignment/individual/persistence/impl/OwnerJdbcDao.java

240 lines
9.1 KiB
Java

package at.ac.tuwien.sepm.assignment.individual.persistence.impl;
import at.ac.tuwien.sepm.assignment.individual.entity.Horse;
import at.ac.tuwien.sepm.assignment.individual.entity.Owner;
import at.ac.tuwien.sepm.assignment.individual.exception.NotFoundException;
import at.ac.tuwien.sepm.assignment.individual.exception.PersistenceException;
import at.ac.tuwien.sepm.assignment.individual.persistence.OwnerDao;
import java.lang.invoke.MethodHandles;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
@Repository
public class OwnerJdbcDao implements OwnerDao {
private static final String TABLE_NAME = "Owner";
private static final String HORSE_TABLE_NAME = "Horse";
private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private final JdbcTemplate jdbcTemplate;
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Autowired
public OwnerJdbcDao(JdbcTemplate jdbcTemplate, NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
}
@Override
public Owner findOneById(Long id) {
LOGGER.debug("Get owner with id {}", id);
final String sql = "SELECT * FROM " + TABLE_NAME + " WHERE id=?";
List<Owner> owners = jdbcTemplate.query(sql, new Object[] { id }, this::mapRow);
if (owners.isEmpty()) throw new NotFoundException("Could not find owner with id " + id);
return owners.get(0);
}
@Override
public List<Owner> getAll() throws NotFoundException {
LOGGER.debug("Get all owners");
final String sql = "SELECT * FROM " + TABLE_NAME;
List<Owner> owners = jdbcTemplate.query(sql, new Object[] { }, this::mapRow);
if(owners.isEmpty()) throw new NotFoundException("No owners found in the database");
return owners;
}
@Override
public List<Owner> getFiltered(Map<String, String> filters) throws NotFoundException {
LOGGER.debug("Get all owners with filters " + filters.entrySet());
final String sql = "SELECT * FROM " + TABLE_NAME + " WHERE UPPER(name) LIKE :name";
// Create a list to hold the results
List<Owner> owners = new ArrayList<>();
// Create a map to hold the sql filters with all values set as wildcards
Map<String, String> queryFilters = new HashMap<>();
queryFilters.put("name", "%_%");
// Go through the supplied filters and find set values
if(filters.get("name") != null)
queryFilters.replace("name", '%' + filters.get("name").toUpperCase() + '%');
// Create an map sql parameter source for use in the query
MapSqlParameterSource sqlMap = new MapSqlParameterSource();
sqlMap.addValues(queryFilters);
owners = namedParameterJdbcTemplate.query(sql, sqlMap, this::mapRow);
if(owners.isEmpty()) throw new NotFoundException("No owners found in the database");
return owners;
}
@Override
public List<Horse> getOwnedHorses(Long id) throws NotFoundException {
LOGGER.debug("Get all horses for owner with id " + id);
final String sql = "SELECT * FROM " + HORSE_TABLE_NAME + " WHERE owner_id=?";
List<Horse> horses = jdbcTemplate.query(sql, new Object[] {id}, BeanPropertyRowMapper.newInstance(Horse.class));
if (horses.isEmpty()) throw new NotFoundException("Could not find horses for owner with id " + id);
return horses;
}
@Override
public Owner addOwner(Owner owner) {
LOGGER.debug("Add owner {}", owner);
final String sql = "INSERT INTO " + TABLE_NAME + "(name, created_at, updated_at) VALUES(?,?,?)";
try {
// Check if the constraints are violated
this.validateOwner(owner);
LocalDateTime currentTime = LocalDateTime.now();
owner.setCreatedAt(currentTime);
owner.setUpdatedAt(currentTime);
// Create a key holder to get the key of the new record
KeyHolder keyHolder = new GeneratedKeyHolder();
int changes = jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
ps.setString(1, owner.getName().trim());
ps.setObject(2, owner.getCreatedAt());
ps.setObject(3, owner.getUpdatedAt());
return ps;
}, keyHolder);
if (changes == 0)
throw new PersistenceException("Creating owner failed, no rows affected");
owner.setId(((Number)keyHolder.getKeys().get("id")).longValue());
return owner;
} catch (DataAccessException e) {
throw new PersistenceException("Adding new records failed", e);
}
}
@Override
public Owner updateOwner(Owner owner) throws DataAccessException {
LOGGER.debug("Update owner {}", owner.toString());
String sql = "UPDATE " + TABLE_NAME + " SET name=?, updated_at=? WHERE id=?";
try {
if(owner.getId() == null || owner.getId() == 0)
throw new DataIntegrityViolationException("Owner Id missing or 0");
this.validateOwner(owner);
Owner oldOwner = findOneById(owner.getId());
LocalDateTime currentTime = LocalDateTime.now();
owner.setUpdatedAt(currentTime);
int changes = jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(sql);
ps.setString(1, owner.getName().trim());
ps.setObject(2, owner.getUpdatedAt());
ps.setObject(3, owner.getId());
return ps;
});
if (changes == 0)
throw new PersistenceException("Updating owner failed, no rows affected");
owner.setCreatedAt(oldOwner.getCreatedAt());
return owner;
} catch(DataAccessException e) {
throw new PersistenceException("Updating records failed", e);
}
}
@Override
public void deleteOwner(Long id) throws DataAccessException, NotFoundException {
Owner ownerToDelete = this.findOneById(id);
LOGGER.debug("Delete owner with id {}", id);
final String sql = "DELETE FROM " + TABLE_NAME + " WHERE id=?";
if (ownerOwnsHorses(id))
throw new DataIntegrityViolationException("Deleting owner failed, owner has horses assigned");
try {
int changes = jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(sql);
ps.setLong(1, id);
return ps;
});
if (changes == 0)
throw new PersistenceException("Deleting owner failed, no rows affected");
} catch(DataAccessException e){
throw new PersistenceException("Deleting records failed", e);
}
}
private void validateOwner(Owner owner) throws DataIntegrityViolationException {
if(owner.getName() == null || owner.getName().isEmpty())
throw new DataIntegrityViolationException("Required parameters for owner missing");
}
private boolean ownerOwnsHorses(Long ownerId) {
final String sql = "SELECT * FROM " + HORSE_TABLE_NAME + " WHERE owner_id=?";
try {
jdbcTemplate.queryForObject(sql, new Object[] {ownerId}, BeanPropertyRowMapper.newInstance(Horse.class));
} catch(EmptyResultDataAccessException e) {
// If empty, return false
return false;
} catch (IncorrectResultSizeDataAccessException e) {
// If incorrect size above 0, return true
return true;
}
return true;
}
private Owner mapRow(ResultSet resultSet, int i) throws SQLException {
final Owner owner = new Owner();
owner.setId(resultSet.getLong("id"));
owner.setName(resultSet.getString("name"));
owner.setCreatedAt(resultSet.getTimestamp("created_at").toLocalDateTime());
owner.setUpdatedAt(resultSet.getTimestamp("updated_at").toLocalDateTime());
return owner;
}
}