Commit 3a71f877 authored by PECQUOT's avatar PECQUOT
Browse files

Merge branch 'release/3.7.0'

parents cf8a59cf 910eb89b
## Sprint 73 - v3.7.0
- Aucune mise à jour de base de données
## Sprint 72 - v3.6.2
- Aucune mise à jour de base de données
......
......@@ -10,7 +10,7 @@
<groupId>fr.ifremer.reefdb</groupId>
<artifactId>reefdb</artifactId>
<version>3.6.2</version>
<version>3.7.0</version>
<packaging>pom</packaging>
<name>Reef DB</name>
......@@ -178,7 +178,7 @@
<maven.compiler.debug>true</maven.compiler.debug>
<!-- Quadrige3 Core version -->
<quadrige3-core.version>3.3.6</quadrige3-core.version>
<quadrige3-core.version>3.4.1</quadrige3-core.version>
<!-- Last ReefDb launcher version -->
<launcherVersion>3.0.3</launcherVersion>
......
......@@ -4,7 +4,7 @@
<parent>
<groupId>fr.ifremer.reefdb</groupId>
<artifactId>reefdb</artifactId>
<version>3.6.2</version>
<version>3.7.0</version>
</parent>
<artifactId>reefdb-core</artifactId>
......
......@@ -989,4 +989,8 @@ public final class ReefDbConfiguration extends QuadrigeCoreConfiguration {
return applicationConfig.getOption(ReefDbConfigurationOption.ALTERNATIVE_TAXON_ORIGIN_PAMPA.getKey());
}
public URL getSismerURL() {
return applicationConfig.getOptionAsURL(ReefDbConfigurationOption.SISMER_WEBSITE_URL.getKey());
}
}
......@@ -381,6 +381,13 @@ public enum ReefDbConfigurationOption implements ConfigOptionDef {
String.class,
false),
SISMER_WEBSITE_URL(
"reefdb.campaign.sismer.url",
n("reefdb.config.option.campaign.sismer.url.description"),
"http://dx.doi.org/",
URL.class,
false),
// EXTRACTION
EXTRACTION_FILE_PREFIX(
......
......@@ -23,6 +23,7 @@ package fr.ifremer.reefdb.dao.administration.user;
* #L%
*/
import fr.ifremer.quadrige3.core.dao.administration.user.DepartmentDao;
import fr.ifremer.reefdb.dto.referential.DepartmentDTO;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
......@@ -33,7 +34,7 @@ import java.util.List;
* <p>ReefDbDepartmentDao interface.</p>
*
*/
public interface ReefDbDepartmentDao {
public interface ReefDbDepartmentDao extends DepartmentDao {
String ALL_DEPARTMENTS_CACHE = "all_departments";
String DEPARTMENT_BY_ID_CACHE = "department_by_id";
......
......@@ -27,13 +27,15 @@ import com.google.common.collect.Lists;
import fr.ifremer.quadrige3.core.dao.administration.user.DepartmentImpl;
import fr.ifremer.quadrige3.core.dao.data.photo.Photo;
import fr.ifremer.quadrige3.core.dao.data.photo.PhotoDaoImpl;
import fr.ifremer.quadrige3.core.dao.data.samplingoperation.SamplingOperationImpl;
import fr.ifremer.quadrige3.core.dao.data.survey.Survey;
import fr.ifremer.quadrige3.core.dao.data.survey.SurveyImpl;
import fr.ifremer.quadrige3.core.dao.referential.*;
import fr.ifremer.quadrige3.core.dao.technical.Assert;
import fr.ifremer.quadrige3.core.dao.technical.Images;
import fr.ifremer.reefdb.config.ReefDbConfiguration;
import fr.ifremer.reefdb.dao.technical.Daos;
import fr.ifremer.reefdb.dao.referential.ReefDbReferentialDao;
import fr.ifremer.reefdb.dao.technical.Daos;
import fr.ifremer.reefdb.dto.ReefDbBeanFactory;
import fr.ifremer.reefdb.dto.ReefDbBeans;
import fr.ifremer.reefdb.dto.data.photo.PhotoDTO;
......@@ -107,14 +109,11 @@ public class ReefDbPhotoDaoImpl extends PhotoDaoImpl implements ReefDbPhotoDao {
@Override
public void savePhotosBySurveyId(int surveyId, Collection<PhotoDTO> photos) {
if (CollectionUtils.isEmpty(photos)) {
return;
}
Survey survey = get(SurveyImpl.class, surveyId);
List<Integer> existingPhotosIds = ReefDbBeans.collectIds(getPhotosBySurveyId(surveyId));
if (photos != null) {
for (PhotoDTO source : photos) {
// remove from existing
......@@ -129,6 +128,7 @@ public class ReefDbPhotoDaoImpl extends PhotoDaoImpl implements ReefDbPhotoDao {
}
}
}
// remove the not saved
if (CollectionUtils.isNotEmpty(existingPhotosIds)) {
......@@ -148,10 +148,12 @@ public class ReefDbPhotoDaoImpl extends PhotoDaoImpl implements ReefDbPhotoDao {
}
// mandatory fields
target.setSurvey(survey);
if (photo.getSamplingOperation() != null) {
// link the photo to the sampling operation
target.setObjectType(load(ObjectTypeImpl.class, Daos.SAMPLING_OPERATION_OBJECT_TYPE));
target.setObjectId(photo.getSamplingOperation().getId());
target.setSamplingOperation(load(SamplingOperationImpl.class, photo.getSamplingOperation().getId()));
} else {
// if no sampling operation provided, link the photo to the survey
target.setObjectType(load(ObjectTypeImpl.class, Daos.SURVEY_OBJECT_TYPE));
......@@ -180,53 +182,50 @@ public class ReefDbPhotoDaoImpl extends PhotoDaoImpl implements ReefDbPhotoDao {
photo.setId(target.getPhotoId());
// compute target file name
String targetFilePath = Daos.computePhotoFilePath(photo, target);
if (!targetFilePath.equals(photo.getPath())) {
// if file path differs, seems to be a new file to copy or replace
File sourceFile = new File(photo.getPath());
boolean move = false;
// if the source file doesn't exists, it could be a already stored photo in db attachment directory
if (!sourceFile.exists() || !sourceFile.isAbsolute()) {
sourceFile = new File(config.getDbAttachmentDirectory(), photo.getPath());
if (sourceFile.exists()) {
// a move will be performed instead of a copy
move = true;
// the other files should be deleted
Images.deleteOtherImage(sourceFile);
}
}
String targetPath = Daos.computePhotoFilePath(photo, target);
if (!targetPath.equals(photo.getPath())) {
// save case :
// 1 - the photo is just imported : path == null and fullPath points to tempDir
// 2 - the photo has been associated to another parent : path == old path where the file should be
File sourceFile = photo.getPath() == null
? new File(photo.getFullPath())
: new File(config.getDbPhotoDirectory(), photo.getPath());
Assert.isTrue(sourceFile.exists(), "photo not found : " + sourceFile);
File targetFile = new File(config.getDbPhotoDirectory(), targetPath);
File targetFile = new File(config.getDbAttachmentDirectory(), targetFilePath);
if (targetFile.exists()) {
// TODO if it's not possible, throw an exception
targetFile.delete();
}
try {
if (move) {
// move existing file
// move main image
FileUtils.moveFile(sourceFile, targetFile);
} else {
// copy new file
FileUtils.copyFile(sourceFile, targetFile);
// try find other images
File mediumSourceFile = Images.getMediumImageFile(sourceFile);
if (mediumSourceFile.exists()) {
File mediumTargetFile = Images.getMediumImageFile(targetFile);
FileUtils.moveFile(mediumSourceFile, mediumTargetFile);
}
File smallSourceFile = Images.getSmallImageFile(sourceFile);
if (smallSourceFile.exists()) {
File smallTargetFile = Images.getSmallImageFile(targetFile);
FileUtils.moveFile(smallSourceFile, smallTargetFile);
}
} catch (IOException ex) {
throw new ReefDbTechnicalException(ex);
}
// prepare new image
Images.prepareImageFile(targetFile);
// update bean
photo.setPath(targetFilePath);
photo.setTempPath(targetFile.getAbsolutePath());
photo.setPath(targetPath);
photo.setFullPath(targetFile.getAbsolutePath());
}
// update photo link if differs
if (!targetFilePath.equals(target.getPhotoLk())) {
if (!targetPath.equals(target.getPhotoLk())) {
target.setPhotoLk(targetFilePath);
target.setPhotoLk(targetPath);
update(target);
}
}
......@@ -237,7 +236,7 @@ public class ReefDbPhotoDaoImpl extends PhotoDaoImpl implements ReefDbPhotoDao {
// delete file
String fileName = get(photoId).getPhotoLk();
if (StringUtils.isNotBlank(fileName)) {
Images.deleteImage(new File(config.getDbAttachmentDirectory(), fileName));
Images.deleteImage(new File(config.getDbPhotoDirectory(), fileName));
}
// then remove entity
......@@ -313,8 +312,8 @@ public class ReefDbPhotoDaoImpl extends PhotoDaoImpl implements ReefDbPhotoDao {
result.setDate(Daos.convertToDate(it.next()));
result.setDirection((String) it.next());
result.setPath((String) it.next());
File fullPath = new File(config.getDbAttachmentDirectory(), result.getPath());
result.setTempPath(fullPath.getPath());
File fullPath = new File(config.getDbPhotoDirectory(), result.getPath());
result.setFullPath(fullPath.getPath());
String photoTypeCode = (String) it.next();
if (StringUtils.isNotBlank(photoTypeCode)) {
......
......@@ -23,9 +23,15 @@ package fr.ifremer.reefdb.dao.data.survey;
* #L%
*/
import fr.ifremer.quadrige3.core.dao.data.survey.CampaignDao;
import fr.ifremer.reefdb.dao.administration.program.ReefDbProgramDao;
import fr.ifremer.reefdb.dao.referential.monitoringLocation.ReefDbMonitoringLocationDao;
import fr.ifremer.reefdb.dto.data.survey.CampaignDTO;
import fr.ifremer.reefdb.dto.data.survey.OccasionDTO;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import java.util.Date;
import java.util.List;
/**
......@@ -33,15 +39,39 @@ import java.util.List;
*
* @author Ludovic
*/
public interface ReefDbCampaignDao {
public interface ReefDbCampaignDao extends CampaignDao {
String ALL_CAMPAIGNS_CACHE = "all_campaigns";
/**
* Return the list of all campaigns
*
* @return a {@link java.util.List} object.
*/
@Cacheable(value = ALL_CAMPAIGNS_CACHE)
List<CampaignDTO> getAllCampaigns();
List<CampaignDTO> getCampaignsByIds(List<Integer> campaignIds);
List<CampaignDTO> getCampaignsByCriteria(String name, Date startDate1, Date startDate2, boolean strictStartDate, Date endDate1, Date endDate2, boolean strictEndDate, boolean canEndDateBeNull);
List<CampaignDTO> getCampaignsByName(String name);
@CacheEvict(value = {
ALL_CAMPAIGNS_CACHE,
ReefDbProgramDao.PROGRAMS_BY_CAMPAIGN_ID_CACHE,
ReefDbMonitoringLocationDao.LOCATIONS_BY_CAMPAIGN_AND_PROGRAM_CACHE
}, allEntries = true)
void saveCampaign(CampaignDTO campaign);
@CacheEvict(value = {
ALL_CAMPAIGNS_CACHE,
ReefDbProgramDao.PROGRAMS_BY_CAMPAIGN_ID_CACHE,
ReefDbMonitoringLocationDao.LOCATIONS_BY_CAMPAIGN_AND_PROGRAM_CACHE
}, allEntries = true)
@Override
void remove(Integer integer);
/**
* Return the list of all occasions
*
......
......@@ -12,32 +12,42 @@ package fr.ifremer.reefdb.dao.data.survey;
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import fr.ifremer.quadrige3.core.dao.administration.user.QuserImpl;
import fr.ifremer.quadrige3.core.dao.data.survey.Campaign;
import fr.ifremer.quadrige3.core.dao.data.survey.CampaignDaoImpl;
import fr.ifremer.quadrige3.core.dao.technical.Assert;
import fr.ifremer.quadrige3.core.dao.technical.hibernate.TemporaryDataHelper;
import fr.ifremer.reefdb.dao.administration.user.ReefDbDepartmentDao;
import fr.ifremer.reefdb.dao.administration.user.ReefDbQuserDao;
import fr.ifremer.reefdb.dao.technical.Daos;
import fr.ifremer.reefdb.dto.ReefDbBeanFactory;
import fr.ifremer.reefdb.dto.data.survey.CampaignDTO;
import fr.ifremer.reefdb.dto.data.survey.OccasionDTO;
import fr.ifremer.reefdb.service.ReefDbDataContext;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.type.StringType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Resource;
import java.util.*;
/**
* <p>ReefDbCampaignDaoImpl class.</p>
......@@ -49,6 +59,15 @@ public class ReefDbCampaignDaoImpl extends CampaignDaoImpl implements ReefDbCamp
private static final Log log = LogFactory.getLog(ReefDbCampaignDaoImpl.class);
@Resource(name = "reefDbQuserDao")
protected ReefDbQuserDao quserDao;
@Resource(name = "reefDbDepartmentDao")
protected ReefDbDepartmentDao departmentDao;
@Resource(name = "reefdbDataContext")
protected ReefDbDataContext dataContext;
/**
* <p>Constructor for ReefDbCampaignDaoImpl.</p>
*
......@@ -59,7 +78,9 @@ public class ReefDbCampaignDaoImpl extends CampaignDaoImpl implements ReefDbCamp
super(sessionFactory);
}
/** {@inheritDoc} */
/**
* {@inheritDoc}
*/
@Override
public List<CampaignDTO> getAllCampaigns() {
Iterator<Object[]> it = queryIterator("allCampaigns");
......@@ -70,10 +91,137 @@ public class ReefDbCampaignDaoImpl extends CampaignDaoImpl implements ReefDbCamp
result.add(toCampaignDTO(Arrays.asList(row).iterator()));
}
return ImmutableList.copyOf(result); // return an immutable list to avoid concurrency modification against cache
}
@Override
@SuppressWarnings("unchecked")
public List<CampaignDTO> getCampaignsByIds(List<Integer> campaignIds) {
List<CampaignDTO> result = Lists.newArrayList();
if (CollectionUtils.isNotEmpty(campaignIds)) {
Query query = createQuery("campaignsByIds").setParameterList("campaignIds", campaignIds);
Iterator<Object[]> it = query.iterate();
while (it.hasNext()) {
result.add(toCampaignDTO(Arrays.asList(it.next()).iterator()));
}
}
return result;
}
/** {@inheritDoc} */
@Override
@SuppressWarnings("unchecked")
public List<CampaignDTO> getCampaignsByCriteria(String name,
Date startDate1, Date startDate2, boolean strictStartDate,
Date endDate1, Date endDate2, boolean strictEndDate, boolean canEndDateBeNull) {
// load query from named query
StringBuilder queryString = new StringBuilder(getSession().getNamedQuery("campaignsByCriteria").getQueryString());
// add start date restriction
StringBuilder startDateString = new StringBuilder();
if (startDate1 != null && startDate2 != null) {
if (startDate1 == startDate2) {
// equals
startDateString.append("campaignStartDt = ").append(Daos.convertDateOnlyToSQLString(startDate1));
} else {
// between
startDateString.append("campaignStartDt >= ").append(Daos.convertDateOnlyToSQLString(startDate1));
startDateString.append(" AND campaignStartDt <= ").append(Daos.convertDateOnlyToSQLString(startDate2));
}
} else if (startDate1 != null) {
// >= or >
startDateString.append("campaignStartDt ").append((strictStartDate ? "> " : ">= ")).append(Daos.convertDateOnlyToSQLString(startDate1));
} else if (startDate2 != null) {
// <= or <
startDateString.append("campaignStartDt ").append((strictStartDate ? "< " : "<= ")).append(Daos.convertDateOnlyToSQLString(startDate2));
}
if (startDateString.length() > 0) {
queryString.append(System.lineSeparator()).append("AND ").append(startDateString);
}
// add end date restriction
StringBuilder endDateString = new StringBuilder();
if (endDate1 != null && endDate2 != null) {
if (endDate1 == endDate2) {
// equals
endDateString.append("campaignEndDt = ").append(Daos.convertDateOnlyToSQLString(endDate1));
} else {
// between
endDateString.append("campaignEndDt >= ").append(Daos.convertDateOnlyToSQLString(endDate1));
endDateString.append(" AND campaignEndDt <= ").append(Daos.convertDateOnlyToSQLString(endDate2));
}
} else if (endDate1 != null) {
// >= or >
endDateString.append("campaignEndDt ").append((strictEndDate ? "> " : ">= ")).append(Daos.convertDateOnlyToSQLString(endDate1));
} else if (endDate2 != null) {
// <= or <
endDateString.append("campaignEndDt ").append((strictEndDate ? "< " : "<= ")).append(Daos.convertDateOnlyToSQLString(endDate2));
}
if (endDateString.length() > 0) {
queryString.append(System.lineSeparator()).append("AND ");
if (canEndDateBeNull) {
queryString.append("(campaignEndDt is null OR (").append(endDateString).append("))");
} else {
queryString.append(endDateString);
}
}
// crete new query from query string
Query q = getSession().createQuery(queryString.toString());
setQueryParams(q, "campaignsByCriteria",
"name", StringType.INSTANCE, name);
Iterator<Object[]> it = q.iterate();
List<CampaignDTO> result = Lists.newArrayList();
while (it.hasNext()) {
Object[] row = it.next();
result.add(toCampaignDTO(Arrays.asList(row).iterator()));
}
return result;
}
@Override
public List<CampaignDTO> getCampaignsByName(String name) {
Iterator<Object[]> it = queryIterator("campaignsByName",
"name", StringType.INSTANCE, name);
List<CampaignDTO> result = new ArrayList<>();
while (it.hasNext()) {
Object[] row = it.next();
result.add(toCampaignDTO(Arrays.asList(row).iterator()));
}
return result;
}
@Override
public void saveCampaign(CampaignDTO campaign) {
Assert.notNull(campaign);
Campaign target = null;
boolean isNew = false;
if (campaign.getId() != null) {
target = get(campaign.getId());
}
if (target == null) {
target = Campaign.Factory.newInstance();
target.setCampaignId(TemporaryDataHelper.getNewNegativeIdForTemporaryData(getSession(), target.getClass()));
isNew = true;
}
beanToEntity(campaign, target);
if (isNew) {
getSession().save(target);
campaign.setId(target.getCampaignId());
} else {
getSession().update(target);
}
}
/**
* {@inheritDoc}
*/
@Override
public List<OccasionDTO> getAllOccasions() {
......@@ -89,12 +237,35 @@ public class ReefDbCampaignDaoImpl extends CampaignDaoImpl implements ReefDbCamp
}
// Private Methods
private void beanToEntity(CampaignDTO source, Campaign target) {
target.setCampaignNm(source.getName());
target.setCampaignStartDt(source.getStartDate());
target.setCampaignEndDt(source.getEndDate());
target.setCampaignSismerLk(source.getSismerLink());
target.setCampaignCm(source.getComment());
target.setQuser(load(QuserImpl.class, source.getManager().getId()));
// Recorder Department (Mantis #42614 Only if REC_DEP_ID is null)
if (target.getRecorderDepartment() == null) {
Assert.notNull(dataContext.getRecorderDepartmentId());
target.setRecorderDepartment(departmentDao.get(dataContext.getRecorderDepartmentId()));
}
}
private CampaignDTO toCampaignDTO(Iterator<Object> iterator) {
CampaignDTO result = ReefDbBeanFactory.newCampaignDTO();
result.setId((Integer) iterator.next());
result.setName((String) iterator.next());
result.setStartDate(Daos.convertToDate(iterator.next()));
result.setEndDate(Daos.convertToDate(iterator.next()));
result.setSismerLink((String) iterator.next());
result.setComment((String) iterator.next());
result.setManager(quserDao.getUserById((Integer) iterator.next()));
result.setRecorderDepartment(departmentDao.getDepartmentById((Integer) iterator.next()));
return result;
}
......
......@@ -78,6 +78,10 @@ public interface ReefDbSurveyDao extends SurveyExtendDao {
*/
Long countSurveysWithProgramAndLocations(String programCode, List<Integer> locationIds);
Long countSurveysWithProgramLocationAndOutsideDates(String programCode, int appliedStrategyId, int locationId, Date startDate, Date endDate);
Long countSurveysWithProgramLocationAndInsideDates(String programCode, int appliedStrategyId, int locationId, Date startDate, Date endDate);
/**
* Get a full survey by its Id
*
......
......@@ -74,6 +74,7 @@ import org.apache.commons.logging.LogFactory;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.type.DateType;
import org.hibernate.type.IntegerType;
import org.hibernate.type.StringType;
import org.springframework.beans.factory.InitializingBean;
......@@ -281,6 +282,28 @@ public class ReefDbSurveyDaoImpl extends SurveyDaoImpl implements ReefDbSurveyDa
return (Long) q.uniqueResult();
}
@Override
public Long countSurveysWithProgramLocationAndOutsideDates(String programCode, int appliedStrategyId, int locationId, Date startDate, Date endDate) {
return queryCount("countSurveysByProgramLocationAndOutsideDates",
"programCode", StringType.INSTANCE, programCode,
"locationId", IntegerType.INSTANCE, locationId,
"appliedStrategyId", IntegerType.INSTANCE, appliedStrategyId,
"startDate", DateType.INSTANCE, startDate,
"endDate", DateType.INSTANCE, endDate);
}