package de.dala.simplenews.utilities; import android.os.AsyncTask; import android.os.Handler; import android.os.Message; import android.util.Log; import com.rometools.rome.feed.synd.SyndEntry; import com.rometools.rome.feed.synd.SyndFeed; import com.rometools.rome.io.SyndFeedInput; import com.rometools.rome.io.XmlReader; import java.net.URL; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import de.dala.simplenews.common.Category; import de.dala.simplenews.common.Entry; import de.dala.simplenews.common.Feed; import de.dala.simplenews.database.DatabaseHandler; import de.dala.simplenews.database.IDatabaseHandler; public class CategoryUpdater { public static final int CANCEL = -2; public static final int ERROR = -1; public static final int EMPTY = 0; public static final int RESULT = 4; public static final int PART_RESULT = 5; private final Handler handler; private final Category category; private final IDatabaseHandler databaseHandler; private boolean isRunning = false; private UpdatingTask task; private final Long deprecatedTime; public CategoryUpdater(Handler handler, Category category) { this.handler = handler; this.category = category; databaseHandler = DatabaseHandler.getInstance(); deprecatedTime = PrefUtilities.getInstance().getDeprecatedTime(); } public void start() { if (isRunning) { return; } isRunning = true; task = new UpdatingTask(); task.execute(); } private void getPartResult(List<Entry> entries) { if (entries != null && !entries.isEmpty()) { sendMessage(entries, PART_RESULT); } } private void sendMessage(Object message, int type) { Message msg = new Message(); msg.what = type; msg.obj = message; handler.sendMessage(msg); } public boolean isRunning() { return isRunning; } public void cancel() { if (isRunning) { if (task != null) { task.cancel(true); } isRunning = false; sendMessage(null, CANCEL); } } private class UpdatingTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { if (error(category)) { return null; } List<Callable<List<Entry>>> futures = new ArrayList<>(); for (final Feed feed : category.getFeeds()) { futures.add(new FeedFutureTask(feed)); } try { List<Entry> entries = new ArrayList<>(); List<Future<List<Entry>>> results = Executors .newFixedThreadPool(category.getFeeds().size()) .invokeAll(futures, 10, TimeUnit.SECONDS); for (Future<List<Entry>> future : results) { if (isCancelled()) { return null; } try { if (!future.isCancelled()) { List<Entry> result = future.get(5, TimeUnit.SECONDS); if (result != null) { entries.addAll(result); } } } catch (CancellationException ignored) { } } finishUpdate(entries); } catch (Exception e) { if (!isCancelled()) { sendMessage(null, ERROR); } } return null; } private boolean error(Category category) { if (category == null || category.getFeeds() == null) { sendMessage(null, ERROR); return true; } if (category.getFeeds().isEmpty()) { sendMessage(null, EMPTY); return true; } return false; } } private void finishUpdate(List<Entry> entries) { if (!entries.isEmpty()) { category.setLastUpdateTime(new Date().getTime()); databaseHandler.updateCategory(category); sendMessage(entries, RESULT); } else { sendMessage(null, EMPTY); } isRunning = false; } private class FeedFutureTask implements Callable<List<Entry>> { final SyndFeedInput input = new SyndFeedInput(); final Feed mFeed; FeedFutureTask(Feed feed) { mFeed = feed; } @Override public List<Entry> call() throws Exception { List<Entry> feedEntries = new ArrayList<>(); try { SyndFeed syndFeed = input.build(new XmlReader(new URL(mFeed.getXmlUrl()))); String title = syndFeed.getTitle(); if (mFeed.getTitle() == null) { mFeed.setTitle(title); databaseHandler.updateFeed(mFeed); } for (SyndEntry item : syndFeed.getEntries()) { Entry entry = Utilities.getEntryFromRSSItem(item, mFeed.getId(), title, category.getId()); if (entry == null) { continue; } if (deprecatedTime == null || (entry.getDate() != null && entry.getDate() > deprecatedTime)) { feedEntries.add(entry); } } } catch (Exception e) { Log.e("CategoryUpdater", "XmlReader could not read feed", e); return null; } databaseHandler.removeEntries(category.getId(), mFeed.getId(), null); databaseHandler.addEntries(category.getId(), mFeed.getId(), feedEntries); getPartResult(feedEntries); return feedEntries; } } }