/* * © University of Bristol */ package org.ilrt.mca.harvester.events; import com.hp.hpl.jena.datatypes.xsd.XSDDatatype; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.rdf.model.ModelFactory; import com.hp.hpl.jena.rdf.model.RDFNode; import com.hp.hpl.jena.rdf.model.ResIterator; import com.hp.hpl.jena.rdf.model.Resource; import com.hp.hpl.jena.rdf.model.ResourceFactory; import com.hp.hpl.jena.rdf.model.Statement; import com.hp.hpl.jena.rdf.model.StmtIterator; import com.hp.hpl.jena.vocabulary.DC; import com.hp.hpl.jena.vocabulary.RDF; import org.apache.log4j.Logger; import org.ilrt.mca.Common; import org.ilrt.mca.dao.AbstractDao; import org.ilrt.mca.harvester.Harvester; import org.ilrt.mca.harvester.HttpResolverImpl; import org.ilrt.mca.harvester.Resolver; import org.ilrt.mca.harvester.xml.XmlSource; import org.ilrt.mca.rdf.DataManager; import org.ilrt.mca.vocab.EVENT; import org.ilrt.mca.vocab.MCA_REGISTRY; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; /** * @author cmcpb */ public class EventHarvesterImpl extends AbstractDao implements Harvester { public EventHarvesterImpl(DataManager manager) throws IOException { resolver = new HttpResolverImpl(); this.manager = manager; findSources = loadSparql("/sparql/findHarvestableEvents.rql"); } @Override public void harvest() { // new date to keep track of the visit Date lastVisited = new Date(); // query registry for list of feeds to harvest // get the date that they were last updated List<XmlSource> sources = findSources(); log.info("Found " + sources.size() + " sources to harvest"); // harvest each source for (XmlSource source : sources) { log.info("Request to harvest: <" + source.getUrl() + ">"); String xsl = source.getXsl(); if (xsl != null && xsl.length() > 0) { xsl = "/" + xsl.substring(6, xsl.length()); } // harvest the data Model model = resolver.resolve(source, new EventResponseHandlerImpl(xsl)); if (model != null) { generateRepeatingEvents(model, source.getUrl()); //System.out.println("AFTER"); //model.write(System.out); // delete the old data manager.deleteAllInGraph(source.getUrl()); // add the harvested data manager.add(source.getUrl(), model); // update the last visited date RDFNode date = ModelFactory.createDefaultModel() .createTypedLiteral(Common.parseXsdDate(lastVisited), XSDDatatype.XSDdateTime); manager.updatePropertyInGraph(Common.AUDIT_GRAPH_URI, source.getUrl(), DC.date, date); } else { log.info("Unable to cache " + source.getUrl()); } } } private void generateRepeatingEvents(Model model, String graphUri) { Date oneMonthFromNow = getEndDate("ONEMONTH"); StmtIterator stmtiter = model.listStatements(null, RDF.type, EVENT.event); Model newEvents = ModelFactory.createDefaultModel(); while (stmtiter.hasNext()) { Statement statement = stmtiter.nextStatement(); Resource r = statement.getSubject(); EventItemImpl calEvent = eventItemDetails(r, graphUri); // create repeating items if (calEvent.isRecurring()) { // generate the repeating events for this item List<Date> dates = calEvent.getRecurringDatesUntil(oneMonthFromNow); long diff = 0; if (calEvent.getEndDate() != null) { // Calculate expectedEndDate; Calendar start = Calendar.getInstance(); start.setTime(calEvent.getStartDate()); long milis1 = calEvent.getStartDate().getTime(); long milis2 = calEvent.getEndDate().getTime(); diff = milis2 - milis1; } int count = 0; for (Date d : dates) { EventItemImpl repeatEvent = calEvent.clone(); repeatEvent.setStartDate(d); if (calEvent.getEndDate() != null) { Calendar end = Calendar.getInstance(); // add diff ms here end.setTimeInMillis(d.getTime() + diff); repeatEvent.setEndDate(end.getTime()); } // create a unique id repeatEvent.setId(repeatEvent.getId() + "_" + (count++)); // store cached copy in dataManager Model newEventModel = ModelFactory.createDefaultModel(); Resource newRes = ResourceFactory.createResource(); newEventModel.add(newRes, RDF.type, EVENT.event); newEventModel.add(newRes, EVENT.UID, ResourceFactory.createPlainLiteral(repeatEvent.getId())); newEventModel.add(newRes, EVENT.subject, ResourceFactory.createPlainLiteral(repeatEvent.getLabel())); if (repeatEvent.getDescription() != null) newEventModel.add(newRes, EVENT.description, ResourceFactory.createPlainLiteral(repeatEvent.getDescription())); if (repeatEvent.getLocation() != null) newEventModel.add(newRes, EVENT.location, ResourceFactory.createPlainLiteral(repeatEvent.getLocation())); if (repeatEvent.getOrganiser() != null) newEventModel.add(newRes, EVENT.organizerName, ResourceFactory.createPlainLiteral(repeatEvent.getOrganiser())); Resource startDate = ResourceFactory.createResource(); newEventModel.add(newRes, newEventModel.createProperty(EVENT.NS + "dtstart"), startDate); newEventModel.add(startDate, EVENT.dateTime, ResourceFactory.createPlainLiteral(Common.parseXsdDate(repeatEvent.getStartDate()))); if (repeatEvent.getEndDate() != null) { Resource endDate = ResourceFactory.createResource(); newEventModel.add(newRes, newEventModel.createProperty(EVENT.NS + "dtend"), endDate); newEventModel.add(endDate, EVENT.dateTime, ResourceFactory.createPlainLiteral(Common.parseXsdDate(repeatEvent.getEndDate()))); } newEvents.add(newEventModel); } } // END if (calEvent.isRecurring()) if (r.hasProperty(EVENT.startDate)) { Resource rDate = r.getProperty(EVENT.startDate).getResource(); // If resource has a date property, change to dateTime if (rDate.hasProperty(EVENT.date)) { String strDate = rDate.getProperty(EVENT.date).getLiteral().getLexicalForm(); try { rDate.addProperty( EVENT.dateTime, ResourceFactory.createPlainLiteral( Common.parseXsdDate(Common.parseDate(strDate)))); } catch (ParseException e) { log.error("Unable to parse: " + strDate + " : " + e.getMessage()); } } } if (r.hasProperty(EVENT.endDate)) { Resource rDate = r.getProperty(EVENT.endDate).getResource(); // If resource has a date property, change to dateTime if (rDate.hasProperty(EVENT.date)) { String strDate = rDate.getProperty(EVENT.date).getLiteral().getLexicalForm(); try { rDate.addProperty( EVENT.dateTime, ResourceFactory.createPlainLiteral( Common.parseXsdDate(Common.parseDate(strDate)))); } catch (ParseException e) { log.error("Unable to parse: " + strDate + " : " + e.getMessage()); } } } } model.add(newEvents); } private List<XmlSource> findSources() { List<XmlSource> sources = new ArrayList<XmlSource>(); Model m = manager.find(findSources); if (!m.isEmpty()) { ResIterator iterator = m.listSubjectsWithProperty(RDF.type); while (iterator.hasNext()) { sources.add(getDetails(iterator.nextResource())); } } return sources; } private XmlSource getDetails(Resource resource) { Date lastVisited = null; String uri = resource.getURI(); String xslSource = ""; if (resource.hasProperty(MCA_REGISTRY.lastVisitedDate)) { try { lastVisited = Common.parseXsdDate(resource.getProperty(MCA_REGISTRY.lastVisitedDate).getLiteral().getLexicalForm()); } catch (ParseException e) { log.error(e.getMessage()); } } if (resource.hasProperty(MCA_REGISTRY.hasXslSource)) { xslSource = resource.getProperty(MCA_REGISTRY.hasXslSource).getResource().getURI(); } return new XmlSource(uri, xslSource, lastVisited); } public EventItemImpl eventItemDetails(Resource resource, String provenance) { EventItemImpl item = new EventItemImpl(); getBasicDetails(resource, item); // override default id with uid from ical. // resource.getURI() returns null anyway. item.setId(resource.getProperty(EVENT.UID).getLiteral().getLexicalForm()); item.setProvenance(provenance); if (resource.hasProperty(EVENT.startDate)) { Resource startDate = resource.getProperty(EVENT.startDate).getResource(); String strDate = ""; if (startDate.hasProperty(EVENT.date)) { strDate = startDate.getProperty(EVENT.date).getLiteral().getLexicalForm(); } if (startDate.hasProperty(EVENT.dateTime)) { strDate = startDate.getProperty(EVENT.dateTime).getLiteral().getLexicalForm(); } try { item.setStartDate(Common.parseDate(strDate)); } catch (ParseException e) { log.error("Unable to parse: " + strDate + " : " + e.getMessage()); } } if (resource.hasProperty(EVENT.endDate)) { Resource endDate = resource.getProperty(EVENT.endDate).getResource(); String strDate = ""; if (endDate.hasProperty(EVENT.date)) { strDate = endDate.getProperty(EVENT.date).getLiteral().getLexicalForm(); } if (endDate.hasProperty(EVENT.dateTime)) { strDate = endDate.getProperty(EVENT.dateTime).getLiteral().getLexicalForm(); } try { item.setEndDate(Common.parseDate(strDate)); } catch (ParseException e) { log.error("Unable to parse: " + strDate + " : " + e.getMessage()); } } if (resource.hasProperty(EVENT.subject)) { item.setLabel(resource.getProperty(EVENT.subject).getString()); } if (resource.hasProperty(EVENT.organizerName)) { item.setOrganiser(resource.getProperty(EVENT.organizerName).getLiteral().getLexicalForm()); } if (resource.hasProperty(EVENT.organizerEmail)) { item.setType(resource.getProperty(EVENT.organizerEmail).getLiteral().getLexicalForm()); } if (resource.hasProperty(EVENT.location)) { item.setLocation(resource.getProperty(EVENT.location).getLiteral().getLexicalForm()); } if (resource.hasProperty(EVENT.description)) { item.setDescription(resource.getProperty(EVENT.description).getLiteral().getLexicalForm()); } if (resource.hasProperty(EVENT.rrule)) { Resource rrule = resource.getProperty(EVENT.rrule).getResource(); // set recurring event properties if (rrule.hasProperty(EVENT.frequency)) { item.setFrequency(rrule.getProperty(EVENT.frequency).getLiteral().getLexicalForm()); } if (rrule.hasProperty(EVENT.until)) { String strDate = rrule.getProperty(EVENT.until).getLiteral().getLexicalForm(); try { item.setUntil(Common.parseDate(strDate)); } catch (ParseException e) { log.error("Unable to parse: " + strDate + " : " + e.getMessage()); } } if (rrule.hasProperty(EVENT.byDay)) { item.setByDays(rrule.getProperty(EVENT.byDay).getLiteral().getLexicalForm()); } if (rrule.hasProperty(EVENT.byMonth)) { item.setByMonth(rrule.getProperty(EVENT.byMonth).getLiteral().getLexicalForm()); } } return item; } private Date getStartDate() { Calendar cal = Calendar.getInstance(); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); return cal.getTime(); } private Date getEndDate(String s) { Calendar endCal = Calendar.getInstance(); if (s.equalsIgnoreCase("TODAY")) { endCal.set(Calendar.HOUR_OF_DAY, 23); endCal.set(Calendar.MINUTE, 59); endCal.set(Calendar.SECOND, 59); endCal.set(Calendar.MILLISECOND, 999); } if (s.equalsIgnoreCase("ONEMONTH")) endCal.add(Calendar.MONTH, 1); return endCal.getTime(); } private Resolver resolver; private DataManager manager; private String findSources; final private Logger log = Logger.getLogger(EventHarvesterImpl.class); }