/* * This is eMonocot, a global online biodiversity information resource. * * Copyright © 2011–2015 The Board of Trustees of the Royal Botanic Gardens, Kew and The University of Oxford * * eMonocot is free software: you can redistribute it and/or modify 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. * * eMonocot 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 Affero General Public License for more details. * * The complete text of the GNU Affero General Public License is in the source repository as the file * ‘COPYING’. It is also available from <http://www.gnu.org/licenses/>. */ package org.emonocot.service.impl; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import org.emonocot.api.ResourceService; import org.emonocot.api.job.CouldNotLaunchJobException; import org.emonocot.api.job.JobExecutionException; import org.emonocot.api.job.JobLaunchRequest; import org.emonocot.api.job.JobLauncher; import org.emonocot.api.job.ResourceAlreadyBeingHarvestedException; import org.emonocot.model.registry.Resource; import org.emonocot.persistence.dao.ResourceDao; import org.joda.time.DateTime; import org.joda.time.base.BaseDateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.core.BatchStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * * @author ben * */ @Service public class ResourceServiceImpl extends SearchableServiceImpl<Resource, ResourceDao> implements ResourceService { private static Logger logger = LoggerFactory.getLogger(ResourceServiceImpl.class); private static BaseDateTime PAST_DATETIME = new DateTime(2010, 11, 1, 9, 0, 0, 0); private JobLauncher jobLauncher; /** * * @param newJobDao Set the image dao */ @Autowired public final void setJobDao(final ResourceDao newJobDao) { super.dao = newJobDao; } @Autowired @Qualifier("messageBasedReadWriteJobLauncher") public void setJobLauncher(JobLauncher jobLauncher) { this.jobLauncher = jobLauncher; } /** * @param sourceId Set the source identifier * @return the total number of jobs for a given source */ @Transactional(readOnly = true) public final Long count(final String sourceId) { return dao.count(sourceId); } /** * @param sourceId * Set the source identifier * @param page * Set the offset (in size chunks, 0-based), optional * @param size * Set the page size * @return A list of jobs */ @Transactional(readOnly = true) public final List<Resource> list(final String sourceId, final Integer page, final Integer size) { return dao.list(sourceId, page, size); } /** * @param id Set the job id * @return the job */ @Transactional(readOnly = true) public final Resource findByJobId(final Long id) { return dao.findByJobId(id); } @Transactional(readOnly = true) public boolean isHarvesting() { return dao.isHarvesting(); } @Transactional(readOnly = true) public List<Resource> listResourcesToHarvest(Integer limit, DateTime now, String fetch) { return dao.listResourcesToHarvest(limit,now,fetch); } @Override @Transactional(readOnly = false) public void harvestResource(Long resourceId, Boolean ifModified) throws ResourceAlreadyBeingHarvestedException, CouldNotLaunchJobException { Resource resource = load(resourceId,"job-with-source"); if (resource.getStatus() != null) { switch (resource.getStatus()) { case STARTED: case STARTING: case STOPPING: case UNKNOWN: throw new ResourceAlreadyBeingHarvestedException(); case COMPLETED: case FAILED: case STOPPED: case ABANDONED: default: break; } } Map<String, String> jobParametersMap = new HashMap<String, String>(); jobParametersMap.put("authority.name", resource.getOrganisation().getIdentifier()); jobParametersMap.put("attempt", UUID.randomUUID().toString()); // Prevent jobs failing if a job has been executed with the same parameters jobParametersMap.put("authority.uri", resource.getUri()); jobParametersMap.put("resource.identifier", resource.getIdentifier()); jobParametersMap.put("skip.unmodified", ifModified.toString()); if (resource.getStatus() == null || !ifModified || resource.getStartTime() == null) { jobParametersMap.put("timestamp", Long.toString(System.currentTimeMillis())); jobParametersMap.put("authority.last.harvested", Long.toString((PAST_DATETIME.getMillis()))); } else { jobParametersMap.put("authority.last.harvested",Long.toString((resource.getStartTime().getMillis()))); } jobParametersMap.putAll(resource.getParameters()); JobLaunchRequest jobLaunchRequest = new JobLaunchRequest(); jobLaunchRequest.setJob(resource.getResourceType().getJobName()); jobLaunchRequest.setParameters(jobParametersMap); try { jobLauncher.launch(jobLaunchRequest); resource.setStartTime(null); resource.setLastAttempt(new DateTime()); resource.setDuration(null); resource.setExitCode(null); resource.setExitDescription(null); resource.setJobId(null); resource.setStatus(BatchStatus.UNKNOWN); resource.setRecordsRead(0); resource.setReadSkip(0); resource.setProcessSkip(0); resource.setWriteSkip(0); resource.setWritten(0); saveOrUpdate(resource); } catch (JobExecutionException e) { throw new CouldNotLaunchJobException(e.getMessage()); } } @Transactional(readOnly = true) public Resource findByResourceUri(String identifier) { return dao.findResourceByUri(identifier); } @Override @PreAuthorize("hasRole('PERMISSION_ADMINISTRATE')") @Transactional(readOnly = false) public void deleteById(Long id) { super.deleteById(id); } @Override @PreAuthorize("hasRole('PERMISSION_ADMINISTRATE')") @Transactional(readOnly = false) public void delete(String identifier) { super.delete(identifier); } }