view src/main/java/de/mpiwg/itgroup/annotations/neo4j/AnnotationStore.java @ 4:3599b29c393f

store seems to work now :-)
author casties
date Mon, 02 Jul 2012 22:39:46 +0200
parents
children bbf0cc5bee29
line wrap: on
line source

/**
 * 
 */
package de.mpiwg.itgroup.annotations.neo4j;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.log4j.Logger;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.Transaction;
import org.neo4j.graphdb.index.Index;
import org.neo4j.graphdb.index.IndexHits;

import de.mpiwg.itgroup.annotations.Annotation;
import de.mpiwg.itgroup.annotations.Annotation.FragmentTypes;

/**
 * @author casties
 * 
 */
public class AnnotationStore {

    protected static Logger logger = Logger.getLogger(AnnotationStore.class);

    protected GraphDatabaseService graphDb;

    public static enum RelationTypes implements RelationshipType {
        ANNOTATES, CREATED
    }

    public static String ANNOTATION_URI_BASE = "http://entities.mpiwg-berlin.mpg.de/annotations/";

    public AnnotationStore(GraphDatabaseService graphDb) {
        super();
        this.graphDb = graphDb;
    }

    public Annotation getAnnotationById(String id) {
        Index<Node> idx = graphDb.index().forNodes("annotations");
        Node annotNode = idx.get("id", id).getSingle();
        Annotation annot = createAnnotation(annotNode);
        return annot;
    }

    /**
     * Returns an Annotation object from an annotation-Node.
     * 
     * @param annotNode
     * @return
     */
    public Annotation createAnnotation(Node annotNode) {
        Annotation annot = new Annotation();
        annot.setUri((String) annotNode.getProperty("id", null));
        annot.setBodyText((String) annotNode.getProperty("bodyText", null));
        annot.setBodyUri((String) annotNode.getProperty("bodyUri", null));
        Iterable<Relationship> targets = annotNode.getRelationships(RelationTypes.ANNOTATES);
        for (Relationship target : targets) {
            annot.setTargetBaseUri((String) target.getProperty("uri", null));
            break;
        }
        annot.setTargetFragment((String) annotNode.getProperty("targetFragment", null));
        String ft = (String) annotNode.getProperty("fragmentType", null);
        if (ft != null) {
            annot.setFragmentType(FragmentTypes.valueOf(ft));
        }
        Iterable<Relationship> creators = annotNode.getRelationships(RelationTypes.CREATED);
        for (Relationship creator : creators) {
            annot.setCreatorUri((String) creator.getProperty("uri", null));
            break;
        }
        annot.setCreated((String) annotNode.getProperty("created", null));
        return annot;
    }

    /**
     * Store a new annotation in the store or update an existing one. Returns
     * the stored annotation.
     * 
     * @param annot
     * @return
     */
    public Annotation storeAnnotation(Annotation annot) {
        Transaction tx = graphDb.beginTx();
        Node annotNode = null;
        String id = annot.getUri();
        if (id == null) {
            id = createRessourceURI("annot:");
        }
        annotNode = createAnnotationNode(id);

        try {
            // Mutating operations go here
            /*
             * the annotation body
             */
            String bodyText = annot.getBodyText();
            if (bodyText != null) {
                annotNode.setProperty("bodyText", bodyText);
            }
            String bodyUri = annot.getBodyUri();
            if (bodyUri != null) {
                annotNode.setProperty("bodyUri", bodyUri);
            }

            /*
             * the annotation target
             */
            String targetBaseUri = annot.getTargetBaseUri();
            if (targetBaseUri != null) {
                Node target = createTargetNode(targetBaseUri);
                annotNode.createRelationshipTo(target, RelationTypes.ANNOTATES);
            }

            /*
             * The fragment part of the annotation target.
             */
            String targetFragment = annot.getTargetFragment();
            FragmentTypes fragmentType = annot.getFragmentType();
            if (targetFragment != null) {
                annotNode.setProperty("targetFragment", targetFragment);
                annotNode.setProperty("fragmentType", fragmentType.name());
            }

            /*
             * The URI of the creator of this annotation.
             */
            String creatorUri = annot.getCreatorUri();
            if (creatorUri != null) {
                Node creator = createPersonNode(creatorUri, null);
                creator.createRelationshipTo(annotNode, RelationTypes.CREATED);
            }

            /*
             * The creation date of this annotation.
             */
            String created = annot.getCreated();
            if (created != null) {
                annotNode.setProperty("created", created);
            }

            tx.success();
        } finally {
            tx.finish();
        }

        // re-read and return annotation
        Annotation storedAnnot = createAnnotation(annotNode);
        return storedAnnot;
    }

    /**
     * Deletes the annotation with the id.
     * 
     * @param id
     */
    public void deleteById(String id) {
        // TODO Auto-generated method stub

    }

    /**
     * Returns all annotations with the given uri and/or user.
     * 
     * @param uri
     * @param userUri
     * @param limit
     * @param offset
     * @return
     */
    public List<Annotation> searchByUriUser(String targetUri, String userUri, String limit, String offset) {
        List<Annotation> annotations = new ArrayList<Annotation>();
        if (targetUri != null) {
            Index<Node> targetIdx = graphDb.index().forNodes("targets");
            // there should be only one
            Node target = targetIdx.get("uri", targetUri).getSingle();
            if (target != null) {
                Iterable<Relationship> relations = target.getRelationships(RelationTypes.ANNOTATES);
                for (Relationship relation: relations) {
                    Node ann = relation.getStartNode();
                    if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
                        Annotation annot = createAnnotation(ann);
                        annotations.add(annot);
                    } else {
                        logger.error("ANNOTATES relation does not start with ANNOTATION: "+ann);
                    }
                }
            }
        }
        if (userUri != null) {
            Index<Node> persIdx = graphDb.index().forNodes("persons");
            // there should be only one
            Node person = persIdx.get("uri", userUri).getSingle();
            if (person != null) {
                Iterable<Relationship> relations = person.getRelationships(RelationTypes.CREATED);
                for (Relationship relation: relations) {
                    Node ann = relation.getEndNode();
                    if (ann.getProperty("TYPE", "").equals("ANNOTATION")) {
                        Annotation annot = createAnnotation(ann);
                        annotations.add(annot);
                    } else {
                        logger.error("CREATED relation does not end with ANNOTATION: "+ann);
                    }
                }
            }
        }
        return annotations;
    }

    protected Node createAnnotationNode(String id) {
        Index<Node> idx = graphDb.index().forNodes("annotations");
        IndexHits<Node> annotations = idx.get("id", id);
        Node annotation = annotations.getSingle();
        if (annotation == null) {
            // does not exist yet
            Transaction tx = graphDb.beginTx();
            try {
                annotation = graphDb.createNode();
                annotation.setProperty("TYPE", "ANNOTATION");
                annotation.setProperty("id", id);
                idx.add(annotation, "id", id);
                tx.success();
            } finally {
                tx.finish();
            }
        }
        return annotation;
    }

    protected Node createTargetNode(String uri) {
        Index<Node> idx = graphDb.index().forNodes("targets");
        IndexHits<Node> targets = idx.get("uri", uri);
        Node target = targets.getSingle();
        if (target == null) {
            // does not exist yet
            Transaction tx = graphDb.beginTx();
            try {
                target = graphDb.createNode();
                target.setProperty("TYPE", "TARGET");
                target.setProperty("uri", uri);
                idx.add(target, "uri", uri);
                tx.success();
            } finally {
                tx.finish();
            }
        }
        return target;
    }

    protected Node createPersonNode(String uri, String name) {
        Index<Node> idx = graphDb.index().forNodes("persons");
        // Person is identified by URI
        IndexHits<Node> persons = idx.get("uri", uri);
        Node person = persons.getSingle();
        if (person == null) {
            // does not exist yet
            Transaction tx = graphDb.beginTx();
            try {
                person = graphDb.createNode();
                person.setProperty("TYPE", "PERSON");
                person.setProperty("uri", uri);
                idx.add(person, "uri", uri);
                if (name != null) {
                    person.setProperty("name", name);
                }
                tx.success();
            } finally {
                tx.finish();
            }
        }
        return person;
    }

    /**
     * Erzeuge eine urn aus der aktuellen Zeit in millis
     * 
     * @return
     */
    private String createRessourceURI(String prefix) {

        Calendar cal = Calendar.getInstance();

        long time = cal.getTimeInMillis();

        return String.format("%s%s%s", ANNOTATION_URI_BASE, prefix, time);

    }


}