ac.simons.tweetarchive.tweets.TweetStorageService.java Source code

Java tutorial

Introduction

Here is the source code for ac.simons.tweetarchive.tweets.TweetStorageService.java

Source

/*
 * Copyright 2016 michael-simons.eu.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ac.simons.tweetarchive.tweets;

import ac.simons.tweetarchive.tweets.TweetEntity.InReplyTo;
import java.time.ZoneId;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import twitter4j.Place;
import twitter4j.Status;
import twitter4j.URLEntity;

/**
 * Parses {@link Status statuses} and their raw json representation and creates
 * {@link TweetEntity tweet entities}.
 *
 * @author Michael J. Simons, 2016-09-05
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class TweetStorageService {

    /**
     * Pattern to extract the source from a tweet.
     */
    private static final Pattern SOURCE_PATTERN = Pattern.compile("<a.*?>(.*)</a>");

    private final TweetRepository tweetRepository;

    @Transactional
    public TweetEntity store(final Status status, final String rawContent) {
        final Optional<TweetEntity> existingTweet = this.tweetRepository.findOne(status.getId());
        if (existingTweet.isPresent()) {
            final TweetEntity rv = existingTweet.get();
            log.warn("Tweet with status {} already existed...", rv.getId());
            return rv;
        }

        final TweetEntity tweet = new TweetEntity(status.getId(), status.getUser().getId(),
                status.getUser().getScreenName(), status.getCreatedAt().toInstant().atZone(ZoneId.of("UTC")),
                extractContent(status), extractSource(status), rawContent);
        tweet.setCountryCode(Optional.ofNullable(status.getPlace()).map(Place::getCountryCode).orElse(null));
        if (status.getInReplyToStatusId() != -1L && status.getInReplyToUserId() != -1L
                && status.getInReplyToScreenName() != null) {
            tweet.setInReplyTo(new InReplyTo(status.getInReplyToStatusId(), status.getInReplyToScreenName(),
                    status.getInReplyToUserId()));
        }
        tweet.setLang(status.getLang());
        tweet.setLocation(Optional.ofNullable(status.getGeoLocation())
                .map(g -> new TweetEntity.Location(g.getLatitude(), g.getLongitude())).orElse(null));
        // TODO Handle quoted tweets
        return this.tweetRepository.save(tweet);
    }

    @Transactional
    public void delete(final long id) {
        long count = this.tweetRepository.deleteById(id);
        log.info("Deleted {} status...", count);
    }

    String extractContent(final Status status) {
        // TODO Handle quoted tweets
        final Status workStatus;
        if (status.isRetweet()) {
            workStatus = status.getRetweetedStatus();
        } else {
            workStatus = status;
        }

        final StringBuilder rv = new StringBuilder();

        final String text = workStatus.getText();
        int pos = 0;
        for (URLEntity urlEntity : workStatus.getURLEntities()) {
            rv.append(text.substring(pos, urlEntity.getStart()));
            rv.append(urlEntity.getExpandedURL());
            pos = urlEntity.getEnd();

        }
        if (pos <= text.length()) {
            rv.append(text.substring(pos, text.length()));
        }

        if (status.isRetweet()) {
            rv.insert(0, String.format("RT @%s: ", workStatus.getUser().getScreenName()));
        }
        return rv.toString();
    }

    String extractSource(final Status status) {
        return Optional.ofNullable(status.getSource()).map(String::trim).filter(s -> !s.isEmpty())
                .map(SOURCE_PATTERN::matcher).filter(Matcher::matches).map(m -> m.group(1).trim()).orElse(null);
    }
}