/*
* 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.portal.scheduling;
import java.text.ParseException;
import java.util.ArrayList;
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.JobLaunchRequest;
import org.emonocot.api.job.JobLauncher;
import org.emonocot.model.registry.Resource;
import org.joda.time.DateTime;
import org.quartz.CronExpression;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerContext;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.BatchStatus;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class HarvestDataJob extends QuartzJobBean {
/**
* The minimal interval in hours between job runs.
*/
private static final int MINIMAL_INTERVAL = 6;
private Logger logger = LoggerFactory.getLogger(HarvestDataJob.class);
private List<String> cronExpressions = new ArrayList<String>();
private String jobLauncherName;
private String resourceServiceName;
public void setWorkingWeekCronExpression(String workingWeekCronExpression) {
this.cronExpressions.add(workingWeekCronExpression);
}
public void seWeekendCronExpression(String weekendCronExpression) {
this.cronExpressions.add(weekendCronExpression);
}
public void setResourceServiceName(String resourceServiceName) {
this.resourceServiceName = resourceServiceName;
}
public void setJobLauncherName(String jobLauncherName) {
this.jobLauncherName = jobLauncherName;
}
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext)
throws JobExecutionException {
try {
SchedulerContext schedulerContext = jobExecutionContext.getScheduler().getContext();
ApplicationContext applicationContext = (ApplicationContext) schedulerContext.get("applicationContext");
ResourceService resourceService = (ResourceService) applicationContext.getBean(resourceServiceName);
JobLauncher jobLauncher = (JobLauncher) applicationContext.getBean(jobLauncherName);
logger.info("HarvestDataJob");
for (String cronExpression : cronExpressions) {
CronExpression expression = new CronExpression(cronExpression);
DateTime now = new DateTime();
if (expression.isSatisfiedBy(now.toDate()) && !resourceService.isHarvesting()) {
DateTime nextInvalidDate = new DateTime(expression.getNextInvalidTimeAfter(now.toDate()));
logger.info(cronExpression + " is satified and resourceService is not harvesting, looking for jobs to harvest . . .");
List<Resource> resourcesToHarvest = resourceService.listResourcesToHarvest(10, now,"job-with-source");
Resource resource = null;
for (Resource r : resourcesToHarvest) {
DateTime probableFinishingTime = now.plus(r.getDuration());
if (probableFinishingTime.isBefore(nextInvalidDate) && (r.getLastAttempt() == null || r.getLastAttempt().plusHours(MINIMAL_INTERVAL).isBefore(now))) {
resource = r;
break;
}
}
if (resource != null) {
logger.info("Found that we can harvest " + resource.getTitle());
Map<String, String> jobParametersMap = new HashMap<String, String>();
jobParametersMap.put("authority.name", resource.getOrganisation().getIdentifier());
jobParametersMap.put("authority.uri", resource.getUri());
jobParametersMap.put("resource.identifier", resource.getIdentifier());
jobParametersMap.put("attempt", UUID.randomUUID().toString()); // Prevent jobs failing if a job has been executed with the same parameters
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.setLastAttempt(now);
resource.setStartTime(null);
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);
resourceService.saveOrUpdate(resource);
} catch (org.emonocot.api.job.JobExecutionException jee) {
throw new JobExecutionException(jee);
}
} else {
logger.info("Could not find a resource we can safely harvest in the time available");
}
} else {
logger.info(now + " is not within " + cronExpression + "or resourceService is harvesting, skipping!");
}
}
} catch (ParseException pe) {
throw new JobExecutionException(pe);
} catch (SchedulerException se) {
throw new JobExecutionException(se);
}
}
}