package org.jtheque.movies.persistence.dao.impl;
/*
* Copyright JTheque (Baptiste Wicht)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.jtheque.collections.DaoCollections;
import org.jtheque.collections.DataCollection;
import org.jtheque.movies.persistence.dao.able.IDaoCategories;
import org.jtheque.movies.persistence.dao.able.IDaoMovies;
import org.jtheque.movies.persistence.od.able.Category;
import org.jtheque.movies.persistence.od.able.Movie;
import org.jtheque.movies.persistence.od.impl.MovieCategoryRelation;
import org.jtheque.movies.persistence.od.impl.MovieImpl;
import org.jtheque.movies.utils.PreciseDuration;
import org.jtheque.movies.utils.Resolution;
import org.jtheque.persistence.Entity;
import org.jtheque.persistence.Note;
import org.jtheque.persistence.QueryMapper;
import org.jtheque.persistence.DaoNotes;
import org.jtheque.persistence.DaoPersistenceContext;
import org.jtheque.persistence.utils.CachedJDBCDao;
import org.jtheque.persistence.utils.Query;
import org.jtheque.utils.StringUtils;
import org.jtheque.utils.collections.CollectionUtils;
import org.springframework.jdbc.core.RowMapper;
import javax.annotation.Resource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* A Data Access Object implementation for movies.
*
* @author Baptiste Wicht
*/
public final class DaoMovies extends CachedJDBCDao<Movie> implements IDaoMovies {
private final RowMapper<Movie> rowMapper = new MovieRowMapper();
private final RowMapper<MovieCategoryRelation> relationRowMapper = new RelationRowMapper();
private final QueryMapper queryMapper = new MovieQueryMapper();
private Collection<MovieCategoryRelation> relationsToCategories;
@Resource
private DaoPersistenceContext daoPersistenceContext;
@Resource
private DaoCollections daoCollections;
@Resource
private IDaoCategories daoCategories;
@Resource
private DaoNotes daoNotes;
/**
* Construct a new DaoMovies.
*/
public DaoMovies() {
super(TABLE);
}
@Override
public Collection<Movie> getMovies() {
List<Movie> films = getMovies(daoCollections.getCurrentCollection());
Collections.sort(films);
return films;
}
/**
* Return all the films of the collection.
*
* @param collection The collection.
*
* @return A List containing all the films of the collections.
*/
private List<Movie> getMovies(DataCollection collection) {
if (collection == null || !collection.isSaved()) {
return (List<Movie>) getAll();
}
load();
List<Movie> movies = new ArrayList<Movie>(getCache().values());
CollectionUtils.filter(movies, new CollectionFilter<Movie>(collection));
return movies;
}
@Override
public boolean delete(Movie movie) {
daoPersistenceContext.getTemplate().update("DELETE FROM " + MOVIES_CATEGORIES_TABLE + " WHERE THE_MOVIE_FK = ?", movie.getId());
return super.delete(movie);
}
@Override
public Movie getMovie(int id) {
return get(id);
}
@Override
public Movie getMovie(String title) {
for (Movie movie : getMovies()) {
if (movie.getTitle().equals(title)) {
return movie;
}
}
return null;
}
@Override
public void save(Movie movie) {
if (movie.isSaved()) {
super.save(movie);
daoPersistenceContext.getTemplate().update("DELETE FROM " + MOVIES_CATEGORIES_TABLE + " WHERE THE_MOVIE_FK = ?", movie.getId());
} else {
movie.setTheCollection(daoCollections.getCurrentCollection());
super.save(movie);
}
createLinks(movie);
}
/**
* Create the links between the movie and the categories.
*
* @param movie The movie.
*/
private void createLinks(Movie movie) {
for (Category category : movie.getCategories()) {
daoPersistenceContext.getTemplate().update("INSERT INTO " + MOVIES_CATEGORIES_TABLE + " (THE_MOVIE_FK, THE_CATEGORY_FK) VALUES(?,?)", movie.getId(), category.getId());
}
}
@Override
public Movie create() {
return new MovieImpl();
}
@Override
protected QueryMapper getQueryMapper() {
return queryMapper;
}
@Override
protected RowMapper<Movie> getRowMapper() {
return rowMapper;
}
@Override
protected void loadCache() {
relationsToCategories = daoPersistenceContext.getTemplate().query("SELECT * FROM " + MOVIES_CATEGORIES_TABLE, relationRowMapper);
Collection<Movie> movies = daoPersistenceContext.getSortedList(TABLE, rowMapper);
for (Movie movie : movies) {
getCache().put(movie.getId(), movie);
}
relationsToCategories.clear();
}
/**
* A row mapper to map a resultset to a relation between category and movie.
*
* @author Baptiste Wicht
*/
private static final class RelationRowMapper implements RowMapper<MovieCategoryRelation> {
@Override
public MovieCategoryRelation mapRow(ResultSet rs, int i) throws SQLException {
MovieCategoryRelation relation = new MovieCategoryRelation();
relation.setMovie(rs.getInt("THE_MOVIE_FK"));
relation.setCategory(rs.getInt("THE_CATEGORY_FK"));
return relation;
}
}
/**
* A row mapper to map a resultset to a movie.
*
* @author Baptiste Wicht
*/
private final class MovieRowMapper implements RowMapper<Movie> {
@Override
public Movie mapRow(ResultSet rs, int i) throws SQLException {
Movie movie = create();
movie.setId(rs.getInt("ID"));
movie.setTitle(rs.getString("TITLE"));
movie.setFile(rs.getString("FILE"));
movie.setImage(rs.getString("IMAGE"));
movie.setTheCollection(daoCollections.getCollection(rs.getInt("THE_COLLECTION_FK")));
if (StringUtils.isNotEmpty(rs.getString("RESOLUTION"))) {
movie.setResolution(new Resolution(rs.getString("RESOLUTION")));
}
if (StringUtils.isNotEmpty(rs.getString("DURATION"))) {
movie.setDuration(new PreciseDuration(rs.getLong("DURATION")));
}
if (StringUtils.isNotEmpty(rs.getString("NOTE"))) {
movie.setNote(Note.fromIntValue(rs.getInt("NOTE")));
} else {
movie.setNote(daoNotes.getDefaultNote());
}
mapRelations(movie);
return movie;
}
/**
* Map the relations of the movie.
*
* @param movie The movie to map the relations for.
*/
private void mapRelations(Movie movie) {
if (relationsToCategories != null && !relationsToCategories.isEmpty()) {
for (MovieCategoryRelation relation : relationsToCategories) {
if (relation.getMovie() == movie.getId()) {
movie.addCategory(daoCategories.getCategory(relation.getCategory()));
}
}
} else {
relationsToCategories = daoPersistenceContext.getTemplate().query("SELECT * FROM " + MOVIES_CATEGORIES_TABLE + " WHERE THE_MOVIE_FK = ?", relationRowMapper, movie.getId());
for (MovieCategoryRelation relation : relationsToCategories) {
movie.addCategory(daoCategories.getCategory(relation.getCategory()));
}
relationsToCategories.clear();
}
}
}
/**
* A query mapper to map movie to requests.
*
* @author Baptiste Wicht
*/
private final class MovieQueryMapper implements QueryMapper {
@Override
public Query constructInsertQuery(Entity entity) {
return new Query(
"INSERT INTO " + TABLE + " (TITLE, NOTE, FILE, RESOLUTION, DURATION, IMAGE, THE_COLLECTION_FK) VALUES(?,?,?,?,?,?,?)",
fillArray((Movie) entity, false));
}
@Override
public Query constructUpdateQuery(Entity entity) {
return new Query(
"UPDATE " + TABLE + " SET TITLE = ?, NOTE = ?, FILE = ?, RESOLUTION = ?, DURATION = ?, IMAGE = ?, THE_COLLECTION_FK = ? WHERE ID = ?",
fillArray((Movie) entity, true));
}
/**
* Fill the array with the informations of the movie.
*
* @param movie The movie to use to fill the array.
* @param id Indicate if we must add the id to the array.
*
* @return The filled array.
*/
private Object[] fillArray(Movie movie, boolean id) {
Object[] values = new Object[7 + (id ? 1 : 0)];
values[0] = movie.getTitle();
values[1] = movie.getNote() == null ? daoNotes.getDefaultNote().intValue() : movie.getNote().intValue();
values[2] = movie.getFile();
values[3] = movie.getResolution() == null ? "" : movie.getResolution().toString();
values[4] = movie.getDuration() == null ? 0 : movie.getDuration().getTime();
values[5] = movie.getImage();
values[6] = movie.getTheCollection().getId();
if (id) {
values[7] = movie.getId();
}
return values;
}
}
}