d09cb0c9d91d1c060b7115d3dcfc0eb00c02fbfe
[pnews.git] / war / src / main / java / pnews / servlet / ArticleProvider.java
1 package pnews.servlet;
2
3 import java.io.IOException;
4 import java.net.MalformedURLException;
5 import java.net.URL;
6 import java.util.ArrayList;
7 import java.util.Collections;
8 import java.util.Comparator;
9 import java.util.Date;
10 import java.util.HashMap;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.concurrent.Executors;
14 import java.util.concurrent.ScheduledExecutorService;
15 import java.util.concurrent.TimeUnit;
16 import java.util.logging.Level;
17 import java.util.logging.Logger;
18
19 import org.jsoup.Jsoup;
20
21 import com.rometools.rome.feed.synd.SyndEnclosure;
22 import com.rometools.rome.feed.synd.SyndEntry;
23 import com.rometools.rome.feed.synd.SyndFeed;
24 import com.rometools.rome.io.FeedException;
25 import com.rometools.rome.io.SyndFeedInput;
26 import com.rometools.rome.io.XmlReader;
27
28 import pnews.Article;
29 import pnews.Category;
30
31 public class ArticleProvider {
32         public final static ArticleProvider singleton = new ArticleProvider();
33         private static final Logger LOG = Logger.getLogger(ArticleProvider.class.getName());
34         private final Map<Category, List<Article>> articlesByCategory = new HashMap<>();
35         private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
36         
37         private ArticleProvider() {      
38                 for (Category cat:Category.values())
39                         scheduler.scheduleAtFixedRate(new Refresher(cat), 2, 120, TimeUnit.SECONDS);
40         }
41         
42         private static SyndFeed getSyndFeed(String u) throws IllegalArgumentException, FeedException, MalformedURLException, IOException {
43                 try (XmlReader reader = new XmlReader(new URL(u))) {
44                         return new SyndFeedInput().build(reader);
45                 }
46         }
47         
48         private static Map<Category, String[]> getFeeds() {
49                 Map<Category, String[]> result;
50                 
51                 result = new HashMap<>();
52                 
53                 result.put(Category.TOP,
54                            new String[] {
55                                            "http://www.francetvinfo.fr/titres.rss",
56                                            "http://www.france24.com/fr/actualites/rss",
57                                            //"https://www.franceinter.fr/rss/a-la-une.xml",
58                                            "http://www.rfi.fr/general/rss",
59                                            "http://www.cnews.fr/rss/une",
60                                            "http://www.bfmtv.com/rss/info/flux-rss/flux-toutes-les-actualites/"
61                            });
62                 
63                 result.put(Category.SPORT,
64                                 new String[] { "http://www.france24.com/fr/sports/rss" });
65                 
66                 result.put(Category.FRANCE,
67                                 new String[] { "http://www.france24.com/fr/france/rss",
68                                                "http://www.rfi.fr/france/rss"});
69                 
70                 result.put(Category.EUROPE,
71                                 new String[] { "http://www.france24.com/fr/europe/rss" });
72                 
73                 result.put(Category.ECO,
74                                 new String[] { "http://www.france24.com/fr/economie/rss",
75                                                "http://www.rfi.fr/economie/rss" });
76                 
77                 result.put(Category.ESSONNE,
78                                 new String[] { /*"https://www.essonneinfo.fr/feed/"*/ });
79                 
80                 result.put(Category.TECHNOLOGIE,
81                                 new String[] { "http://feeds.feedburner.com/lesnumeriques/news",
82                                                "http://www.zdnet.fr/feeds/rss/actualites/"});
83                 
84                 return result;
85         }
86         
87         private void addArticles(Category cat, SyndFeed feed) {
88                 String thumbnail;
89                 String desc;
90                 Date date;
91                 List<Article> articles;
92                 
93                 LOG.info("addArticles" + cat.getId());
94                 
95                 for (SyndEntry entry: feed.getEntries()) {
96                         thumbnail = null;
97                         for (SyndEnclosure e: entry.getEnclosures()) {
98                                 if (e.getType().startsWith("image/"))
99                                         thumbnail = e.getUrl();    
100                                 break;
101                         }
102                                 
103                         if (entry.getDescription() != null) {                             
104                                 desc = Jsoup.parse(entry.getDescription().getValue()).text();
105                         } else {       
106                                 desc = null;
107                                 LOG.severe("No description for " + feed.getTitle() + " - " + entry.getTitle());
108                         }
109                         
110                         date = entry.getPublishedDate();
111                         if (date == null)
112                                 date = entry.getUpdatedDate();
113                         
114                         synchronized(articlesByCategory) {
115                                 articles = articlesByCategory.get(cat);
116                                 if (articles == null) {
117                                         articles = new ArrayList<>();
118                                         articlesByCategory.put(cat, articles);
119                                 } else {                                
120                                         for (Article a: articles)
121                                                 if (a.link.equals(entry.getLink()))
122                                                         return ;
123                                 }
124                                 
125                                 articles.add(new Article(entry.getLink(),
126                                                          cat,
127                                                          entry.getTitle(),
128                                                          desc,
129                                                          thumbnail,
130                                                          date,
131                                                          feed.getTitle()));
132
133                                 
134                                 Collections.sort(articles, new Comparator<Article>() {
135                                         @Override
136                                         public int compare(Article o1, Article o2) {
137                                                 return o2.publicationDate.compareTo(o1.publicationDate);
138                                         }
139                                         
140                                 });
141                         }
142                 }               
143         }
144         
145         private void retrieveArticles(Category cat) throws IllegalArgumentException, MalformedURLException, FeedException, IOException {
146                 String[] feeds;
147                 
148                 feeds = getFeeds().get(cat);
149                 
150                 if (feeds != null)
151                         for (String str: feeds)
152                                 addArticles(cat, getSyndFeed(str));
153                 else
154                         LOG.severe("No feed for category " + cat);
155         }
156         
157         public List<Article> getArticles(Category cat)
158                         throws IllegalArgumentException, MalformedURLException, FeedException, IOException {
159                 synchronized (articlesByCategory) {
160                         return articlesByCategory.get(cat);
161                 }
162         }
163         
164         private class Refresher implements Runnable {
165                 private final Category category;
166                 
167                 public Refresher(Category category) {
168                         this.category = category;
169                 }
170                 
171                 @Override
172                 public void run() {
173                         List<Article> articles;
174                         
175                         LOG.info("refresher "+ category.getId());
176                         
177                         try {
178                                 retrieveArticles(category);
179                                 
180                                 synchronized (articlesByCategory) {
181                                         articles = articlesByCategory.get(category);
182                                         if (articles != null && articles.size() > 100) {
183                                                 articlesByCategory.put(category,
184                                                                        articles.subList(0, 100));
185                                                                 
186                                         }
187                                 }
188                         } catch (IllegalArgumentException | FeedException | IOException e) {
189                                 LOG.log(Level.SEVERE, "refresher failure", e);
190                         }                        
191                         
192                         LOG.info("refresher "+ category.getId() + " done");
193                 }                
194         }
195 }