net.schweerelos.parrot.model.TimedThingsHelper.java Source code

Java tutorial

Introduction

Here is the source code for net.schweerelos.parrot.model.TimedThingsHelper.java

Source

/*
 * Copyright (C) 2011 Andrea Schweer
 *
 * This file is part of the Digital Parrot. 
 *
 * The Digital Parrot is free software; you can redistribute it and/or modify
 * it under the terms of the Eclipse Public License as published by the Eclipse
 * Foundation or its Agreement Steward, either version 1.0 of the License, or
 * (at your option) any later version.
 *
 * The Digital Parrot 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 Eclipse Public License for
 * more details.
 *
 * You should have received a copy of the Eclipse Public License along with the
 * Digital Parrot. If not, see http://www.eclipse.org/legal/epl-v10.html. 
 *
 */

package net.schweerelos.parrot.model;

import net.schweerelos.timeline.model.PayloadInterval;
import net.schweerelos.timeline.model.IntervalChain;

import org.joda.time.DateTime;
import org.joda.time.Interval;

import com.hp.hpl.jena.datatypes.RDFDatatype;
import com.hp.hpl.jena.datatypes.xsd.XSDDateTime;
import com.hp.hpl.jena.ontology.Individual;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntResource;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.NodeIterator;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.util.iterator.ExtendedIterator;

public class TimedThingsHelper {
    private static final String TIMED_THING = "http://parrot.resnet.scms.waikato.ac.nz/Parrot/Terms/TimeAndPlace/2008/11/TimeAndPlace.owl#TimedThing";
    static private final String ABSOLUTELY_TIMED_THING = "http://parrot.resnet.scms.waikato.ac.nz/Parrot/Terms/TimeAndPlace/2008/11/TimeAndPlace.owl#AbsolutelyTimedThing";
    static private final String ENDS_AT = "http://parrot.resnet.scms.waikato.ac.nz/Parrot/Terms/TimeAndPlace/2008/11/TimeAndPlace.owl#endsAt";
    static private final String STARTS_AT = "http://parrot.resnet.scms.waikato.ac.nz/Parrot/Terms/TimeAndPlace/2008/11/TimeAndPlace.owl#startsAt";
    private static final String DURING = "http://parrot.resnet.scms.waikato.ac.nz/Parrot/Terms/TimeAndPlace/2008/11/TimeAndPlace.owl#during";

    public static IntervalChain<NodeWrapper> extractTimedThings(ParrotModel pModel) {
        OntModel model = pModel.getOntModel();
        Resource timedThingClass = model.createClass(TIMED_THING);

        IntervalChain<NodeWrapper> timelineModel = new IntervalChain<NodeWrapper>();
        ExtendedIterator<Individual> instances = model.listIndividuals(timedThingClass);
        while (instances.hasNext()) {
            Individual instance = instances.next();
            final NodeWrapper node = pModel.getNodeWrapper(instance);

            DateTime startsAt;
            DateTime endsAt;
            try {
                startsAt = extractStartDate(instance, model);
            } catch (NotTimedThingException e) {
                // ignore this individual
                continue;
            }
            try {
                endsAt = extractEndDate(instance, model);
            } catch (NotTimedThingException e) {
                // ignore this individual
                continue;
            }

            if (startsAt == null || endsAt == null) {
                // only proceed if we have a start time *and* an end time
                continue;
            }

            if (endsAt.isBefore(startsAt)) {
                System.out.printf(
                        "end timestamp %s is before start timestamp %s, ignoring instance %s as TimedThing\n",
                        endsAt.toString(), startsAt.toString(), instance.getURI());
                continue;
            }
            final Interval base = new Interval(startsAt, endsAt);

            PayloadInterval<NodeWrapper> interval = new PayloadInterval<NodeWrapper>() {
                Interval baseInterval = base;

                @Override
                public DateTime getEnd() {
                    return baseInterval.getEnd();
                }

                @Override
                public DateTime getStart() {
                    return baseInterval.getStart();
                }

                @Override
                public NodeWrapper getPayload() {
                    return node;
                }

                @Override
                public boolean contains(Interval interval) {
                    return baseInterval.contains(interval);
                }

                @Override
                public Interval toInterval() {
                    return baseInterval;
                }

            };
            timelineModel.add(interval);
        }
        return timelineModel;
    }

    /**
     * Determines whether the node is a timedthing with reasonably well-known
     * temporal boundaries. This is the case if the node is an instance of
     * AbsolutelyTimedThing or if it occurred during an AbsolutelyTimedThing.
     * 
     * @param node
     *            the node to check
     * @param model
     *            the ont model from which the node is taken
     * @return true if the node is a timedthing with reasonably well-known
     *         boundaries.
     */
    public static boolean isTimedThing(OntResource node, ParrotModel pModel) {
        OntModel model = pModel.getOntModel();
        if (isAbsolutelyTimedThing(node)) {
            return true;
        }
        return isIndirectlyTimedThing(node, model);
    }

    public static DateTime extractStartDate(OntResource subject, ParrotModel model) throws NotTimedThingException {
        return extractStartDate(subject, model.getOntModel());
    }

    public static DateTime extractEndDate(OntResource subject, ParrotModel model) throws NotTimedThingException {
        return extractEndDate(subject, model.getOntModel());
    }

    private static DateTime extractStartDate(OntResource subject, OntModel model) throws NotTimedThingException {
        if (isAbsolutelyTimedThing(subject)) {
            return extractAbsoluteDate(subject, model, STARTS_AT);
        } else if (isIndirectlyTimedThing(subject, model)) {
            return extractNearestDate(subject, model, STARTS_AT, true);
        }
        throw new NotTimedThingException(subject + " is not a timed thing");
    }

    /**
     * Extracts a {@code DateTime} representation of a date associated with the
     * subject, by iterating through all spanning {@code AbsolutelyTimedThing}s
     * and taking the nearest date. The type of date is specified via its
     * property name.
     * 
     * @param subject
     *            the subject for which the date should be extracted. The
     *            assumption is that the subject is in indirectly timed thing
     *            (ie {@code TimedThingsHelper#isIndirectlyTimedThing(subject,
     *            model)} is true).
     * @param model
     *            the model from which the subject has been taken.
     * @param propertyName
     *            name of the property to use (would normally be {@code
     *            TimedThingsHelper#STARTS_AT} or {@code
     *            TimedThingsHelper#ENDS_AT})
     * @param before
     *            whether the nearest date should be before or after the thing's
     *            time.
     * @return a {@code DateTime} representation of a date associated with the
     *         subject
     * @throws NotTimedThingException
     *             if the subject isn't timed
     */
    private static DateTime extractNearestDate(OntResource subject, OntModel model, String propertyName,
            boolean before) throws NotTimedThingException {
        DateTime currentBestCandidate = null;

        Property duringProperty = model.createProperty(DURING);
        // TODO #42 this should go through before and after as well
        if (!subject.hasProperty(duringProperty)) {
            throw new NotTimedThingException(subject + " doesn't have property " + DURING);
        }
        NodeIterator values = subject.listPropertyValues(duringProperty);
        while (values.hasNext()) {
            RDFNode value = values.next();
            if (isAbsolutelyTimedThing(value)) {
                DateTime valueDate = extractAbsoluteDate(value, model, propertyName);
                boolean betterThanCurrentBest = false;
                if (currentBestCandidate == null) {
                    betterThanCurrentBest = true;
                } else {
                    betterThanCurrentBest = (valueDate.isBefore(currentBestCandidate) == before);
                }
                if (betterThanCurrentBest) {
                    currentBestCandidate = valueDate;
                }
            }
        }
        return currentBestCandidate;
    }

    private static DateTime extractAbsoluteDate(RDFNode subject, OntModel model, String propertyName)
            throws NotTimedThingException {
        if (subject.canAs(OntResource.class)) {
            return extractAbsoluteDate(subject.as(OntResource.class), model, propertyName);
        }
        throw new NotTimedThingException("can't extract date for nodes that aren't OntResources");
    }

    /**
     * Extracts a {@code DateTime} representation of the subject's date. The
     * type of date is specified via its property name.
     * 
     * @param subject
     *            the subject for which a date should be extracted. The
     *            assumption is that this is an absolutely timed thing, ie
     *            {@code #isAbsolutelyTimedThing(subject, model)} is true.
     * @param model
     *            the model from which the subject has been taken.
     * @param propertyName
     *            name of the property to use (would normally be {@code
     *            TimedThingsHelper#STARTS_AT} or {@code
     *            TimedThingsHelper#ENDS_AT})
     * @return a date representation of the subject's value of the specified
     *         property
     * @throws NotTimedThingException
     *             if the subject isn't timed
     */
    private static DateTime extractAbsoluteDate(OntResource subject, OntModel model, String propertyName)
            throws NotTimedThingException {
        Property prop = model.createProperty(propertyName);
        RDFNode propValue = subject.getPropertyValue(prop);
        return extractDate(propValue);
    }

    private static DateTime extractEndDate(OntResource subject, OntModel model) throws NotTimedThingException {
        if (isAbsolutelyTimedThing(subject)) {
            return extractAbsoluteDate(subject, model, ENDS_AT);
        } else if (isIndirectlyTimedThing(subject, model)) {
            return extractNearestDate(subject, model, ENDS_AT, false);
        }
        throw new NotTimedThingException(subject + " is not a timed thing");
    }

    private static boolean isAbsolutelyTimedThing(RDFNode node) {
        if (!node.canAs(OntResource.class)) {
            return false;
        }
        OntResource res = node.as(OntResource.class);
        return isAbsolutelyTimedThing(res);
    }

    private static boolean isAbsolutelyTimedThing(OntResource node) {
        if (!node.isIndividual()) {
            return false;
        }
        Individual individual = node.asIndividual();
        return individual.hasOntClass(ABSOLUTELY_TIMED_THING);
    }

    /**
     * check whether it happened during an AbsolutelyTimedThing
     * 
     * @param node
     * @param model
     * @return
     */
    private static boolean isIndirectlyTimedThing(OntResource node, OntModel model) {
        Property duringProperty = model.createProperty(DURING);
        if (!node.hasProperty(duringProperty)) {
            return false;
        }
        NodeIterator values = node.listPropertyValues(duringProperty);
        while (values.hasNext()) {
            RDFNode value = values.next();
            if (isAbsolutelyTimedThing(value)) {
                return true;
            }
        }
        return false;
    }

    private static DateTime extractDate(RDFNode node) throws NotTimedThingException {
        if (!node.isLiteral()) {
            throw new NotTimedThingException("Node is not a literal");
        }
        RDFDatatype type = ((Literal) node).getDatatype();
        Object value = ((Literal) node).getValue();
        if (type != null && value != null && value instanceof XSDDateTime) {
            return new DateTime(((XSDDateTime) value).asCalendar());
        } else {
            throw new NotTimedThingException("Node does not represent a date");
        }
    }

}