Package net.fortytwo.twitlogic.persistence

Source Code of net.fortytwo.twitlogic.persistence.PersistenceContext

package net.fortytwo.twitlogic.persistence;

import net.fortytwo.twitlogic.TwitLogic;
import net.fortytwo.twitlogic.model.Dollartag;
import net.fortytwo.twitlogic.model.Hashtag;
import net.fortytwo.twitlogic.model.Person;
import net.fortytwo.twitlogic.model.Place;
import net.fortytwo.twitlogic.model.Resource;
import net.fortytwo.twitlogic.model.Tweet;
import net.fortytwo.twitlogic.model.URIReference;
import net.fortytwo.twitlogic.model.User;
import net.fortytwo.twitlogic.model.geo.Point;
import net.fortytwo.twitlogic.persistence.beans.Agent;
import net.fortytwo.twitlogic.persistence.beans.Document;
import net.fortytwo.twitlogic.persistence.beans.Feature;
import net.fortytwo.twitlogic.persistence.beans.Graph;
import net.fortytwo.twitlogic.persistence.beans.Image;
import net.fortytwo.twitlogic.persistence.beans.MicroblogPost;
import net.fortytwo.twitlogic.persistence.beans.SpatialThing;
import net.fortytwo.twitlogic.persistence.beans.UserAccount;
import net.fortytwo.twitlogic.syntax.TweetSyntax;
import net.fortytwo.twitlogic.util.properties.PropertyException;
import org.openrdf.concepts.owl.Thing;
import org.openrdf.elmo.ElmoManager;
import org.openrdf.elmo.Entity;

import javax.xml.namespace.QName;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;

/**
* Note: the (private) "persist" methods of the class use an "add only" approach:
* functional relationships such as names and homepages are only added or
* replaced, never removed.  So if a user removes its homepage link,
* TwitLogic will remember the old homepage until the user chooses a new,
* valid homepage URL.
*
* @author Joshua Shinavier (http://fortytwo.net).
*/
public class PersistenceContext {
    private static final Logger LOGGER = TwitLogic.getLogger(PersistenceContext.class);

    private final ElmoManager manager;
    private final boolean avoidRedundantTypeDesignation;

    public PersistenceContext(final TweetStoreConnection sc) throws PropertyException {
        this.manager = sc.getElmoManager();
        avoidRedundantTypeDesignation = TwitLogic.getConfiguration().getBoolean(
                TwitLogic.AVOID_REDUNDANT_TYPE_DESIGNATION, false);
    }

    public MicroblogPost persist(final Tweet tweet,
                                 final boolean persistGraph) {
        MicroblogPost post = postForTweet(tweet);

        if (persistGraph) {
            post.setEmbedsKnowledge(graphForTweet(tweet));
        }

        if (null != tweet.getCreatedAt()) {
            // TODO: put these in the ISO 8601 format
            post.setCreated(SesameTools.toXMLGregorianCalendar(tweet.getCreatedAt()));
        }

        if (null != tweet.getText()) {
            post.setContent(tweet.getText());
        }

        if (null != tweet.getUser()) {
            UserAccount userAccount = accountForUser(tweet.getUser());
            post.setHasCreator(userAccount);
        }

        if (null != tweet.getInReplyToTweet()) {
            MicroblogPost p = postForTweet(tweet.getInReplyToTweet());
            post.setReplyOf(p);
        }

        // Note: we assume that no tweet will be simultaneously a retweet of one tweet and a reply to another.
        if (null != tweet.getRetweetOf()) {
            MicroblogPost p = postForTweet(tweet.getRetweetOf());
            post.setReplyOf(p);
        }

        Set<Thing> topics = new HashSet<Thing>();
        if (null != tweet.getEntities()) {
            for (Resource t : tweet.getEntities().getTopics()) {
                if (t instanceof Hashtag) {
                    topics.add(persist((Hashtag) t));
                } else if (t instanceof Dollartag) {
                    topics.add(persist((Dollartag) t));
                } else {
                    throw new IllegalStateException("topic of unfamiliar type: " + t);
                }
            }
        }
        post.setTopic(topics);

        Set<Thing> links = new HashSet<Thing>();
        if (null != tweet.getEntities()) {
            for (URIReference t : tweet.getEntities().getLinks()) {
                try {
                    links.add(persist(t));
                } catch (IllegalArgumentException e) {
                    LOGGER.warning("invalid URI: " + t);
                    // Just skip this link.
                }
            }
        }
        post.setLinksTo(links);

        /*
        if (null != tweet.getInReplyToUser()) {
            User user = userForUser(tweet.getInReplyToUser());
            post.setAddressedTo(user);
        }*/

        // TODO: geo

        return post;
    }

    private Agent agentForUser(final User user,
                               final UserAccount account) {
        if (null != user.getScreenName()) {
            account.setId(user.getScreenName());
        }

        Agent agent = account.getAccountOf();

        if (null == agent) {
            agent = agentForUser(user);
            account.setAccountOf(agent);
        }

        return agent;
    }

    public UserAccount persist(final User tweetUser) {
        UserAccount userAccount = accountForUser(tweetUser);

        Agent agent = agentForUser(tweetUser, userAccount);

        Set<Thing> equivalentAgents = new HashSet<Thing>();
        String semanticTweetUri
                = "http://semantictweet.com/" + tweetUser.getScreenName() + "#me";
        equivalentAgents.add(
                designate(semanticTweetUri, Thing.class));
        agent.setOwlSameAs(equivalentAgents);

        if (null != tweetUser.getName()) {
            agent.setName(tweetUser.getName());
        }

        if (null != tweetUser.getDescription()) {
            agent.setRdfsComment(tweetUser.getDescription());
        }

        if (null != tweetUser.getLocation()) {
            SpatialThing basedNear = agent.getBasedNear();
            if (null == basedNear) {
                basedNear = spatialThing();
                agent.setBasedNear(basedNear);
            }

            basedNear.setRdfsComment(tweetUser.getLocation());
        }

        if (null != tweetUser.getUrl()
                && TweetSyntax.URL_PATTERN.matcher(tweetUser.getUrl()).matches()) {
            // Note: we can't easily delete an existing homepage (removing its
            // rdf:type statement), as it might be the homepage of another
            // agent.  Therefore, "orphaned" Document resources are possible.

            Document homepage = designate(tweetUser.getUrl(), Document.class);
            agent.setHomepage(homepage);
        }

        if (null != tweetUser.getProfileImageUrl()
                && TweetSyntax.URL_PATTERN.matcher(tweetUser.getProfileImageUrl()).matches()) {
            // Note: we can't easily delete an existing image (removing its
            // rdf:type statement), as it might be the image of another
            // agent.  Therefore, "orphaned" Image resources are possible.

            Image depiction = designate(tweetUser.getProfileImageUrl(), Image.class);
            agent.setDepiction(depiction);
        }

        if (null != tweetUser.getFollowers()) {
            Set<Agent> agents = new HashSet<Agent>();
            for (User u : tweetUser.getFollowers()) {
                UserAccount ua = accountForUser(u);
                Agent ag = agentForUser(u, ua);
                agents.add(ag);
            }

            agent.setKnownBy(agents);
        }

        if (null != tweetUser.getFollowees()) {
            Set<Agent> agents = new HashSet<Agent>();
            for (User u : tweetUser.getFollowees()) {
                UserAccount ua = accountForUser(u);
                Agent ag = agentForUser(u, ua);
                agents.add(ag);
            }

            agent.setKnows(agents);
        }

        return userAccount;
    }

    public Thing persist(final Dollartag tag) {
        return designate(uriOf(tag), Thing.class);
    }

    public Thing persist(final Hashtag hashtag) {
        return designate(uriOf(hashtag), Thing.class);
    }

    public Thing persist(final URIReference uri) {
        return designate(uri.getValue(), Thing.class);
    }

    public Agent persist(final net.fortytwo.twitlogic.model.Person tweetPerson) {
        User tweetUser = tweetPerson.getAccount();
        UserAccount userAccount = persist(tweetUser);
        return userAccount.getAccountOf();
    }

    public net.fortytwo.twitlogic.persistence.beans.Point persist(final Point point) {
        // TODO: create a URI based on longitude and latitude. It won't be unique due to varying precision, but close enough.
        net.fortytwo.twitlogic.persistence.beans.Point p = point();
        p.setLong(point.getLongitude());
        p.setLat(point.getLatitude());
        return p;
    }

    public Feature persist(final Place place) {
        Feature f = (Feature) designate(uriOf(place), place.getPlaceType().getElmoClass());

        if (null != place.getName()) {
            f.setRdfsLabel(place.getName());
        }

        if (null != place.getFullName()) {
            f.setTitle(place.getFullName());
        }

        if (null != place.getUrl()) {
            Thing t = designate(place.getUrl(), Thing.class);
            // FIXME: I'm not sure how this Object Set is handled
            Set<Object> s = f.getRdfsSeeAlso();
            s.add(t);
            f.setRdfsSeeAlso(s);
        }

        // TODO: link into DBPedia and/or GeoNames
        if (null != place.getCountryCode()) {
            f.setCountryCode(place.getCountryCode());
        }

        /*
        if (null != place.getPlaceType()) {
            org.openrdf.concepts.rdfs.Class c = classForPlaceType(place.getPlaceType());

            if (null != c) {
                Set<org.openrdf.concepts.rdfs.Class> types = f.getRdfTypes();
                types.add(c);
                f.setRdfTypes(types);
            }
        }*/

        // Note: double-typing the feature as a Point is cheating (but it works...)
        if (null != place.getCentroid()) {
            Point c = place.getCentroid();
            net.fortytwo.twitlogic.persistence.beans.Point p
                    = designate(uriOf(place), net.fortytwo.twitlogic.persistence.beans.Point.class);

            p.setLong(c.getLongitude());
            p.setLat(c.getLatitude());
        }

        return f;
    }

    ////////////////////////////////////////////////////////////////////////////

    public MicroblogPost find(final Tweet tweet) {
        Entity e = manager.find(new QName(uriOf(tweet)));
        return null == e
                ? null

                : e instanceof MicroblogPost
                ? (MicroblogPost) e
                : null;
    }

    public UserAccount find(final User user) {
        Entity e = manager.find(new QName(uriOf(user)));
        return null == e
                ? null

                : e instanceof UserAccount
                ? (UserAccount) e
                : null;
    }

    ////////////////////////////////////////////////////////////////////////////

    //private org.openrdf.concepts.rdfs.Class classForPlaceType(final PlaceType type) {
    //    return designate(type.getUri(), org.openrdf.concepts.rdfs.Class.class);
    //}

    private UserAccount accountForUser(final User user) {
        return designate(uriOf(user), UserAccount.class);
    }

    private Agent agentForUser(final User user) {
        return designate(uriOf(user.getHeldBy()), Agent.class);
    }

    private SpatialThing spatialThing() {
        String uri = TwitLogic.LOCATIONS_BASEURI + SesameTools.randomIdString();
        return designate(uri, SpatialThing.class);
    }

    private net.fortytwo.twitlogic.persistence.beans.Point point() {
        String uri = TwitLogic.LOCATIONS_BASEURI + SesameTools.randomIdString();
        return designate(uri, net.fortytwo.twitlogic.persistence.beans.Point.class);
    }

    private MicroblogPost postForTweet(final Tweet tweet) {
        try {
            return designate(uriOf(tweet), MicroblogPost.class);
        } catch (ClassCastException e) {
            throw new IllegalArgumentException("bad value: " + uriOf(tweet), e);
        }
    }

    private Graph graphForTweet(final Tweet tweet) {
        String uri = TwitLogic.GRAPHS_BASEURI + "twitter/" + tweet.getId();
        return designate(uri, Graph.class);
    }

    ////////////////////////////////////////////////////////////////////////////

    private <T> T designate(final String uri,
                            final Class<T> c) {
        // Avoid duplicate rdf:type statements (e.g. in AllegroGraph) by first
        // removing matching rdf:type statements before adding a new one.
        // Note: it is still possible for an entity to have multiple, distinct
        // types (e.g. geo:Feature and geo:Point).
        if (avoidRedundantTypeDesignation) {
            T t = manager.designate(new QName(uri), c);
            manager.removeDesignation(t, c);
            return manager.designate(new QName(uri), c);
        } else {
            return manager.designate(new QName(uri), c);
        }
    }

    ////////////////////////////////////////////////////////////////////////////

    public static String uriOf(final User user) {
        return TwitLogic.USERS_BASEURI + user.getId();
    }

    public static String uriOf(final Person person) {
        return TwitLogic.PERSONS_BASEURI + person.getAccount().getId();
    }

    public static String uriOf(final Tweet tweet) {
        return TwitLogic.TWEETS_BASEURI + tweet.getId();
    }

    public static String uriOf(final Dollartag tag) {
        // FIXME: assumes normalized dollar tags
        return TwitLogic.DOLLARTAGS_BASEURI + tag.getName();
    }

    public static String uriOf(final Hashtag hashtag) {
        // FIXME: assumes normalized hash tags
        return TwitLogic.HASHTAGS_BASEURI + hashtag.getName();
    }

    public static String uriOf(final Place place) {
        return TwitLogic.TWITTER_PLACE_BASEURI + place.getId();
    }
}
TOP

Related Classes of net.fortytwo.twitlogic.persistence.PersistenceContext

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.