package gov.nysenate.openleg.dao.law.data;
import gov.nysenate.openleg.dao.base.*;
import gov.nysenate.openleg.model.law.LawFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static gov.nysenate.openleg.dao.law.data.SqlLawFileQuery.*;
import static gov.nysenate.openleg.util.DateUtils.toDate;
import static gov.nysenate.openleg.util.FileIOUtils.safeListFiles;
import static java.util.stream.Collectors.toList;
@Repository
public class SqlFsLawFileDao extends SqlBaseDao implements LawFileDao
{
private static final Logger logger = LoggerFactory.getLogger(SqlFsLawFileDao.class);
/** Directory where new law files come in. */
private File incomingLawDir;
/** Directory where law files that have been processed are stored. */
private File archiveLawDir;
@PostConstruct
protected void init() {
this.incomingLawDir = new File(environment.getStagingDir(), "laws");
this.archiveLawDir = new File(environment.getArchiveDir(), "laws");
}
/** --- Implemented Methods --- */
/** {@inheritDoc} */
@Override
public List<LawFile> getIncomingLawFiles(SortOrder sortByDate, LimitOffset limitOffset) throws IOException {
List<File> files = new ArrayList<>(safeListFiles(this.incomingLawDir, false, null));
List<LawFile> lawFiles = files.stream().map(LawFile::new).collect(toList());
// Use the comparator defined in LawFile to do the sorting
sortLaws(sortByDate, lawFiles);
lawFiles = LimitOffset.limitList(lawFiles, limitOffset);
return lawFiles;
}
@Override
public List<LawFile> getPendingLawFiles(SortOrder sortByDate, LimitOffset limitOffset) {
OrderBy orderBy = new OrderBy("published_date_time", sortByDate, "file_name", sortByDate);
return jdbcNamed.query(SqlLawFileQuery.GET_PENDING_LAW_FILES.getSql(schema(), orderBy, limitOffset), lawFileRowMapper);
}
/** {@inheritDoc} */
@Override
public void updateLawFile(LawFile lawFile) {
ImmutableParams lawParams = ImmutableParams.from(getLawFileParameters(lawFile));
if (jdbcNamed.update(SqlLawFileQuery.UPDATE_LAW_FILE.getSql(schema()), lawParams) == 0) {
jdbcNamed.update(SqlLawFileQuery.INSERT_LAW_FILE.getSql(schema()), lawParams);
}
}
/** {@inheritDoc} */
@Override
public void archiveAndUpdateLawFile(LawFile lawFile) throws IOException {
// Archive the file only if it's currently in the incoming directory.
File file = lawFile.getFile();
if (file.getParentFile().compareTo(this.incomingLawDir) == 0) {
File archiveFile = getFileInArchiveDir(file.getName());
moveFile(file, archiveFile);
lawFile.setFile(archiveFile);
lawFile.setArchived(true);
updateLawFile(lawFile);
}
else {
throw new FileNotFoundException(
"The source law file must be in the incoming laws directory in order to be archived.");
}
}
/** --- Internal Methods --- */
/**
* Use the comparator defined in LawFile to do the sorting, using the reverse comparator
* if indicated by the sortByDate param.
*/
private void sortLaws(SortOrder sortByDate, List<LawFile> lawFiles) {
if (sortByDate.equals(SortOrder.ASC)) {
Collections.sort(lawFiles);
}
else {
Collections.sort(lawFiles, Collections.reverseOrder());
}
}
/**
* Get file handle from the incoming law directory.
*/
private File getFileInIncomingDir(String fileName) {
return new File(this.incomingLawDir, fileName);
}
/**
* Get file handle from the law archive directory.
*/
private File getFileInArchiveDir(String fileName) {
return new File(this.archiveLawDir, fileName);
}
/** --- Param Source Methods --- */
private MapSqlParameterSource getLawFileParameters(LawFile lawFile) {
MapSqlParameterSource params = new MapSqlParameterSource();
params.addValue("fileName", lawFile.getFileName())
.addValue("publishedDateTime", toDate(lawFile.getPublishedDate()))
.addValue("processedDateTime", toDate(lawFile.getProcessedDateTime()))
.addValue("processedCount", lawFile.getProcessedCount())
.addValue("pendingProcessing", lawFile.isPendingProcessing())
.addValue("archived", lawFile.isArchived());
return params;
}
/** --- Row Mapper Instances --- */
private RowMapper<LawFile> lawFileRowMapper = (rs, rowNum) -> {
String fileName = rs.getString("file_name");
boolean isArchived = rs.getBoolean("archived");
File file = (isArchived) ? getFileInArchiveDir(fileName) : getFileInIncomingDir(fileName);
LawFile lawFile = new LawFile(file);
lawFile.setArchived(isArchived);
lawFile.setPendingProcessing(rs.getBoolean("pending_processing"));
lawFile.setStagedDateTime(getLocalDateTimeFromRs(rs, "staged_date_time"));
lawFile.setProcessedDateTime(getLocalDateTimeFromRs(rs, "processed_date_time"));
lawFile.setProcessedCount(rs.getInt("processed_count"));
return lawFile;
};
}