/*
* Copyright 2012 Eric F. Savage, code@efsavage.com
*
* 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 com.ajah.syndicate.data;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import lombok.extern.java.Log;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ajah.spring.jdbc.err.DataOperationException;
import com.ajah.syndicate.FeedEntry;
import com.ajah.syndicate.FeedEntryId;
import com.ajah.syndicate.FeedSourceId;
import com.ajah.util.AjahUtils;
import com.ajah.util.data.HashUtils;
/**
* Manages persistence of {@link FeedEntry}s.
*
* @author <a href="http://efsavage.com">Eric F. Savage</a>, <a
* href="mailto:code@efsavage.com">code@efsavage.com</a>.
*
*/
@Service
@Log
public class FeedEntryManager {
@Autowired
private FeedEntryDao entryDao;
/**
* Fetches an Entry by the SHA-1 of it's html url.
*
* @param feedSourceId
* The ID of the FeedSource this entry is from.
* @param htmlUrlSha1
* The SHA-1 of the Entry's html url.
* @return The Entry, if found, otherwise null.
* @throws DataOperationException
*/
public FeedEntry findByHtmlUrlSha1(final FeedSourceId feedSourceId, final String htmlUrlSha1) throws DataOperationException {
// TODO this field may not necessarily be unique, order by something?
return this.entryDao.findByHtmlUrlSha1(feedSourceId, htmlUrlSha1);
}
/**
* Finds a list of entries for a feed source with a specified set of
* tags/categories.
*
* @param feedSourceId
* The feed source to search on.
* @param categories
* The categories the entries must have.
* @param orCategories
* If true, the categories are an OR and only one must match,
* otherwise the entry must match all of them.
* @return List of matching entries.
* @throws DataOperationException
* If the query could not be executed.
*/
public List<FeedEntry> list(final FeedSourceId feedSourceId, final String[] categories, final boolean orCategories) throws DataOperationException {
return this.entryDao.list(feedSourceId, categories, orCategories);
}
/**
* Loads an entry by its ID.
*
* @param entryId
* The ID to load.
* @return The entry, will not be null.
* @throws DataOperationException
* If the query could not be executed.
* @throws FeedEntryNotFoundException
* If no entry could be found with the specified ID.
*/
public FeedEntry load(final FeedEntryId entryId) throws DataOperationException, FeedEntryNotFoundException {
final FeedEntry entry = this.entryDao.load(entryId);
if (entry == null) {
throw new FeedEntryNotFoundException(entryId);
}
return entry;
}
/**
* This will attempt to match an Entry to avoid duplicates.
*
* @param candidate
* The entry to try and match.
* @return The entry or the matched replacement.
* @throws DataOperationException
* If a query could not be executed.
*/
public FeedEntry matchAndSave(final FeedEntry candidate) throws DataOperationException {
FeedEntry entry = this.entryDao.findMatch(candidate.getFeedSourceId(), candidate.getHtmlUrlSha1(), candidate.getContentSha1());
if (entry == null) {
entry = this.entryDao.findByHtmlUrlSha1(candidate.getFeedSourceId(), candidate.getHtmlUrlSha1());
}
if (entry == null) {
entry = new FeedEntry();
}
int hash = entry.hashCode();
entry.setContent(candidate.getContent());
entry.setDescription(candidate.getDescription());
entry.setCategories(candidate.getCategories());
entry.setContentSha1(HashUtils.sha1Hex(candidate.getContent() + candidate.getDescription() + candidate.getCategories()));
entry.setFeedId(candidate.getFeedId());
if (entry.hashCode() != hash) {
save(entry);
}
save(entry);
return entry;
}
/**
* Saves an entry, inserting if the ID is not set, otherwise updating. Will
* set created date if that is null.
*
* @param entry
* The entry to save.
* @throws DataOperationException
* if the entry could not be saved.
*/
public void save(final FeedEntry entry) throws DataOperationException {
if (entry.getPublished().getTime() < 0) {
log.warning("Very old date, ignoring");
entry.setPublished(new Date(0));
}
AjahUtils.requireParam(entry.getFeedId(), "entry.feedId");
AjahUtils.requireParam(entry.getFeedSourceId(), "entry.feedSourceId");
if (entry.getCreated() == null) {
entry.setCreated(new Date());
}
if (entry.getId() == null) {
entry.setId(new FeedEntryId(UUID.randomUUID().toString()));
this.entryDao.insert(entry);
} else {
this.entryDao.update(entry);
}
}
}