	public void runHarvest() throws SQLException, IOException, AuthorizeException
	{
		String oaiSource = harvestRow.getOaiSource();
		String oaiSetId = harvestRow.getOaiSetId();
        if("all".equals(oaiSetId))
        {
            oaiSetId = null;
        }
		Date lastHarvestDate = harvestRow.getHarvestDate();
		String fromDate = null;
		if (lastHarvestDate != null)
        {
            fromDate = processDate(harvestRow.getHarvestDate());
        }
		Date startTime = new Date();
		String toDate = processDate(startTime,0);
		String dateGranularity;
		try
		{
			String descMDPrefix = null;
			String OREPrefix;
	    	try {
	    		dateGranularity = oaiGetDateGranularity(oaiSource);
	    		if (fromDate != null)
                {
                    fromDate = fromDate.substring(0, dateGranularity.length());
                }
	    		toDate = toDate.substring(0, dateGranularity.length());
	    		descMDPrefix = oaiResolveNamespaceToPrefix(oaiSource, metadataNS.getURI());
	    		OREPrefix = oaiResolveNamespaceToPrefix(oaiSource, ORESerialNS.getURI());
	    	}
	    	catch (FileNotFoundException fe) {
	    		log.error("The OAI server did not respond.");
	    		throw new HarvestingException("The OAI server did not respond.", fe);
	    	}
	    	catch (ConnectException fe) {
	    		log.error("The OAI server did not respond.");
	    		throw new HarvestingException("The OAI server did not respond.", fe);
	    	}
			if (descMDPrefix == null) {
				log.error("The OAI server does not support this metadata format");
				throw new HarvestingException("The OAI server does not support this metadata format: " + metadataNS.getURI());
			}
			if (OREPrefix == null && harvestRow.getHarvestType() != HarvestedCollection.TYPE_DMD) {
				throw new HarvestingException("The OAI server does not support ORE dissemination in the configured serialization format: " + ORESerialNS.getURI());
			}
			Document oaiResponse = null;
			Element root = null;
			String resumptionToken;
			harvestRow.setHarvestStatus(HarvestedCollection.STATUS_BUSY);
			harvestRow.setHarvestMessage("Collection is currently being harvested");
			harvestRow.setHarvestStartTime(startTime);
			harvestRow.update();
			ourContext.commit();
			int expirationInterval = ConfigurationManager.getIntProperty("oai", "harvester.threadTimeout");
	    	if (expirationInterval == 0)
            {
                expirationInterval = 24;
            }
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(startTime);
			calendar.add(Calendar.HOUR, expirationInterval);
            Date expirationTime = calendar.getTime();
			List<Element> records;
			Set<String> errorSet = new HashSet<String>();
			ListRecords listRecords = new ListRecords(oaiSource, fromDate, toDate, oaiSetId, descMDPrefix);
			log.debug("Harvesting request parameters: listRecords " + oaiSource + " " + fromDate + " " + toDate + " " + oaiSetId + " " + descMDPrefix);
			if (listRecords != null)
            {
                log.info("HTTP Request: " + listRecords.getRequestURL());
            }
			while (listRecords != null)
			{
				records = new ArrayList<Element>();
				oaiResponse = db.build(listRecords.getDocument());
				if (listRecords.getErrors() != null && listRecords.getErrors().getLength() > 0)
				{
					for (int i=0; i<listRecords.getErrors().getLength(); i++)
					{
						String errorCode = listRecords.getErrors().item(i).getAttributes().getNamedItem("code").getTextContent();
						errorSet.add(errorCode);
					}
					if (errorSet.contains("noRecordsMatch"))
					{
						log.info("noRecordsMatch: OAI server did not contain any updates");
						harvestRow.setHarvestResult(new Date(), "OAI server did not contain any updates");
						harvestRow.setHarvestStatus(HarvestedCollection.STATUS_READY);
						harvestRow.update();
						return;
					} else {
						throw new HarvestingException(errorSet.toString());
					}
				}
				else
				{
					root = oaiResponse.getRootElement();
					records.addAll(root.getChild("ListRecords", OAI_NS).getChildren("record", OAI_NS));
				}
				if (records != null && records.size()>0)
				{
					log.info("Found " + records.size() + " records to process");
					for (Element record : records) {
						if (HarvestScheduler.interrupt == HarvestScheduler.HARVESTER_INTERRUPT_STOP)
                        {
                            throw new HarvestingException("Harvest process for " + targetCollection.getID() + " interrupted by stopping the scheduler.");
                        }
						if (expirationTime.before(new Date()))
                        {
                            throw new HarvestingException("runHarvest method timed out for collection " + targetCollection.getID());
                        }
						processRecord(record,OREPrefix);
						ourContext.commit();
					}
				}
				resumptionToken = listRecords.getResumptionToken();
				if (resumptionToken == null || resumptionToken.length() == 0) {
					listRecords = null;
				}
				else {
					listRecords = new ListRecords(oaiSource, resumptionToken);
				}
                ourContext.turnOffAuthorisationSystem();
				targetCollection.update();
                ourContext.restoreAuthSystemState();
				ourContext.commit();
			}
		}
		catch (HarvestingException hex) {
			log.error("Harvesting error occured while processing an OAI record: " + hex.getMessage());
			harvestRow.setHarvestMessage("Error occured while processing an OAI record");
			if (harvestRow.getHarvestMessage().contains("Error")) {
				alertAdmin(HarvestedCollection.STATUS_OAI_ERROR, hex);
			}
			harvestRow.setHarvestStatus(HarvestedCollection.STATUS_OAI_ERROR);
			return;
		}
		catch (Exception ex) {
			harvestRow.setHarvestMessage("Unknown error occured while generating an OAI response");
			harvestRow.setHarvestStatus(HarvestedCollection.STATUS_UNKNOWN_ERROR);
			alertAdmin(HarvestedCollection.STATUS_UNKNOWN_ERROR, ex);
			log.error("Error occured while generating an OAI response: " + ex.getMessage() + " " + ex.getCause());
			ex.printStackTrace();
			return;
		}
		finally {
			harvestRow.update();
            ourContext.turnOffAuthorisationSystem();
			targetCollection.update();
			ourContext.commit();
			ourContext.restoreAuthSystemState();
			ourContext.restoreAuthSystemState();
		}
		Date finishTime = new Date();
		long timeTaken = finishTime.getTime() - startTime.getTime();
		harvestRow.setHarvestResult(startTime, "Harvest from " + oaiSource + " successful");
		harvestRow.setHarvestStatus(HarvestedCollection.STATUS_READY);
		log.info("Harvest from " + oaiSource + " successful. The process took " + timeTaken + " milliseconds.");
		harvestRow.update();
		ourContext.commit();
	}

	public void runHarvest() throws SQLException, IOException, AuthorizeException
	{
		String oaiSource = harvestRow.getOaiSource();
		String oaiSetId = harvestRow.getOaiSetId();
        if("all".equals(oaiSetId))
        {
            oaiSetId = null;
        }
		Date lastHarvestDate = harvestRow.getHarvestDate();
		String fromDate = null;
		if (lastHarvestDate != null)
        {
            fromDate = processDate(harvestRow.getHarvestDate());
        }
		Date startTime = new Date();
		String toDate = processDate(startTime,0);
		String dateGranularity;
		try
		{
			String descMDPrefix = null;
			String OREPrefix;
	    	try {
	    		dateGranularity = oaiGetDateGranularity(oaiSource);
	    		if (fromDate != null)
                {
                    fromDate = fromDate.substring(0, dateGranularity.length());
                }
	    		toDate = toDate.substring(0, dateGranularity.length());
	    		descMDPrefix = oaiResolveNamespaceToPrefix(oaiSource, metadataNS.getURI());
	    		OREPrefix = oaiResolveNamespaceToPrefix(oaiSource, ORESerialNS.getURI());
	    	}
	    	catch (FileNotFoundException fe) {
	    		log.error("The OAI server did not respond.");
	    		throw new HarvestingException("The OAI server did not respond.", fe);
	    	}
	    	catch (ConnectException fe) {
	    		log.error("The OAI server did not respond.");
	    		throw new HarvestingException("The OAI server did not respond.", fe);
	    	}
			if (descMDPrefix == null) {
				log.error("The OAI server does not support this metadata format");
				throw new HarvestingException("The OAI server does not support this metadata format: " + metadataNS.getURI());
			}
			if (OREPrefix == null && harvestRow.getHarvestType() != HarvestedCollection.TYPE_DMD) {
				throw new HarvestingException("The OAI server does not support ORE dissemination in the configured serialization format: " + ORESerialNS.getURI());
			}
			Document oaiResponse = null;
			Element root = null;
			String resumptionToken;
			harvestRow.setHarvestStatus(HarvestedCollection.STATUS_BUSY);
			harvestRow.setHarvestMessage("Collection is currently being harvested");
			harvestRow.setHarvestStartTime(startTime);
			harvestRow.update();
			ourContext.commit();
			int expirationInterval = ConfigurationManager.getIntProperty("oai", "harvester.threadTimeout");
	    	if (expirationInterval == 0)
            {
                expirationInterval = 24;
            }
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(startTime);
			calendar.add(Calendar.HOUR, expirationInterval);
            Date expirationTime = calendar.getTime();
			List<Element> records;
			Set<String> errorSet = new HashSet<String>();
			ListRecords listRecords = new ListRecords(oaiSource, fromDate, toDate, oaiSetId, descMDPrefix);
			log.debug("Harvesting request parameters: listRecords " + oaiSource + " " + fromDate + " " + toDate + " " + oaiSetId + " " + descMDPrefix);
			if (listRecords != null)
            {
                log.info("HTTP Request: " + listRecords.getRequestURL());
            }
			while (listRecords != null)
			{
				records = new ArrayList<Element>();
				oaiResponse = db.build(listRecords.getDocument());
				if (listRecords.getErrors() != null && listRecords.getErrors().getLength() > 0)
				{
					for (int i=0; i<listRecords.getErrors().getLength(); i++)
					{
						String errorCode = listRecords.getErrors().item(i).getAttributes().getNamedItem("code").getTextContent();
						errorSet.add(errorCode);
					}
					if (errorSet.contains("noRecordsMatch"))
					{
						log.info("noRecordsMatch: OAI server did not contain any updates");
						harvestRow.setHarvestResult(new Date(), "OAI server did not contain any updates");
						harvestRow.setHarvestStatus(HarvestedCollection.STATUS_READY);
						harvestRow.update();
						return;
					} else {
						throw new HarvestingException(errorSet.toString());
					}
				}
				else
				{
					root = oaiResponse.getRootElement();
					records.addAll(root.getChild("ListRecords", OAI_NS).getChildren("record", OAI_NS));
				}
				if (records != null && records.size()>0)
				{
					log.info("Found " + records.size() + " records to process");
					for (Element record : records) {
						if (HarvestScheduler.interrupt == HarvestScheduler.HARVESTER_INTERRUPT_STOP)
                        {
                            throw new HarvestingException("Harvest process for " + targetCollection.getID() + " interrupted by stopping the scheduler.");
                        }
						if (expirationTime.before(new Date()))
                        {
                            throw new HarvestingException("runHarvest method timed out for collection " + targetCollection.getID());
                        }
						processRecord(record,OREPrefix);
						ourContext.commit();
					}
				}
				resumptionToken = listRecords.getResumptionToken();
				if (resumptionToken == null || resumptionToken.length() == 0) {
					listRecords = null;
				}
				else {
					listRecords = new ListRecords(oaiSource, resumptionToken);
				}
                ourContext.turnOffAuthorisationSystem();
                try {
                    targetCollection.update();
                } finally {
                    ourContext.restoreAuthSystemState();
                }
				ourContext.commit();
			}
		}
		catch (HarvestingException hex) {
			log.error("Harvesting error occured while processing an OAI record: " + hex.getMessage());
			harvestRow.setHarvestMessage("Error occured while processing an OAI record");
			if (harvestRow.getHarvestMessage().contains("Error")) {
				alertAdmin(HarvestedCollection.STATUS_OAI_ERROR, hex);
			}
			harvestRow.setHarvestStatus(HarvestedCollection.STATUS_OAI_ERROR);
			return;
		}
		catch (Exception ex) {
			harvestRow.setHarvestMessage("Unknown error occured while generating an OAI response");
			harvestRow.setHarvestStatus(HarvestedCollection.STATUS_UNKNOWN_ERROR);
			alertAdmin(HarvestedCollection.STATUS_UNKNOWN_ERROR, ex);
			log.error("Error occured while generating an OAI response: " + ex.getMessage() + " " + ex.getCause());
			ex.printStackTrace();
			return;
		}
		finally {
			harvestRow.update();
            ourContext.turnOffAuthorisationSystem();
			targetCollection.update();
			ourContext.commit();
			ourContext.restoreAuthSystemState();
		}
		Date finishTime = new Date();
		long timeTaken = finishTime.getTime() - startTime.getTime();
		harvestRow.setHarvestResult(startTime, "Harvest from " + oaiSource + " successful");
		harvestRow.setHarvestStatus(HarvestedCollection.STATUS_READY);
		log.info("Harvest from " + oaiSource + " successful. The process took " + timeTaken + " milliseconds.");
		harvestRow.update();
		ourContext.commit();
	}
