Java tutorial
/* Copyright 2006 - 2010 Under Dusken 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 no.dusken.aranea.web.control; import com.sun.syndication.feed.synd.SyndFeed; import com.sun.syndication.io.FeedException; import com.sun.syndication.io.SyndFeedInput; import com.sun.syndication.io.XmlReader; import org.apache.commons.io.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Required; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.ServletRequestUtils; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.AbstractController; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class RssCacheController extends AbstractController { private final static Logger log = LoggerFactory.getLogger(RssCacheController.class); /** * The directory in which to store rss converted to html */ private String cacheDirectory; private Map<String, SyndFeed> cacheMap = new ConcurrentHashMap<String, SyndFeed>(); /** * Number of entries to view. Default is 10 */ private Integer numberOfEntries = 10; /** * Feeds to use if we don't get one in the request */ private Map<String, String> feeds; /** * Get the feed from cache or load from link * @return syndfeed from the given link */ private SyndFeed loadOrGetFromCache(String url, int numberOfEntries) { SyndFeed feed = cacheMap.get(url); if (feed == null) { log.info("Feed was not cached", url); File feedFile = new File(cacheDirectory + "/" + url); try { feed = getFeed(feedFile); } catch (FeedException e) { log.error("Could not parse feed", url, e); } catch (IOException e) { log.error("Feed not on disk", url, e); } } return feed; } public void updateFeeds() { for (String key : feeds.keySet()) { String url = feeds.get(key); SyndFeed feed = null; File feedFile = null; try { feedFile = File.createTempFile(key, "xml"); //download the feed FileUtils.copyURLToFile(new URL(url), feedFile); log.info("loading new rss from url: {}", url); //try to parse it feed = getFeed(feedFile); //cache to memory cacheMap.put(url, feed); // saving the feed in disk cache FileUtils.copyFile(feedFile, new File(cacheDirectory + "/" + url)); } catch (Exception e) { log.error("Could not download rss or rss is invalid, using stored file", e); feedFile = new File(cacheDirectory + "/" + url); try { feed = getFeed(feedFile); cacheMap.put(url, feed); } catch (FeedException e1) { log.error("Epic Fail, could not parse old file", e); } catch (IOException e1) { log.error("All aboard the failboat, the stored file was bad or missing. Poor thing", e); } finally { deleteTempFile(feedFile); } } finally { deleteTempFile(feedFile); } } } private void deleteTempFile(File feedFile) { if (feedFile != null) { feedFile.delete(); } } /** * If urls contain links these will be used, else feeds defined in the context is used. * numberOfEntries can also be set through the request else the value set in context is used */ public ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws ServletRequestBindingException { Map<String, Object> map = new HashMap<String, Object>(); String[] urls = ServletRequestUtils.getStringParameters(request, "url"); int numOfEntriesFromrequest = ServletRequestUtils.getIntParameter(request, "numberOfEntries", 0); if (numOfEntriesFromrequest != 0) { map.put("numberOfEntries", numOfEntriesFromrequest); } else { map.put("numberOfEntries", numberOfEntries); } Map<String, SyndFeed> feedMap = new HashMap<String, SyndFeed>(); if (urls.length != 0) { for (String f : urls) { SyndFeed feed = loadOrGetFromCache(f, numberOfEntries); feedMap.put(feed.getTitle(), feed); } } else { for (String f : feeds.keySet()) { feedMap.put(f, loadOrGetFromCache(feeds.get(f), numberOfEntries)); } } map.put("feeds", feedMap); return new ModelAndView("no/dusken/aranea/base/web/rss/view", map); } public void setNumberOfEntries(Integer number) { this.numberOfEntries = number; } /** * Takes a file and tries to parse it to a SyndFeed. * If it does so successfully it stores the file. * @param feedFile * @return Syndfeed * @throws FeedException if parsing fails * @throws IOException if there is IO error with file. */ private SyndFeed getFeed(File feedFile) throws FeedException, IOException { SyndFeedInput input = new SyndFeedInput(); SyndFeed feed = input.build(new XmlReader(feedFile)); feed.setEncoding("UTF-8"); //the new feedfile is valid, save it. File storeFeedFile = new File(cacheDirectory + "/" + feedFile.getName()); if (!storeFeedFile.getCanonicalPath().equals(feedFile.getCanonicalPath())) { FileUtils.copyFile(feedFile, storeFeedFile); } return feed; } @Required public void setCacheDirectory(String dir) { this.cacheDirectory = dir; } public void setFeeds(Map<String, String> feeds) { this.feeds = feeds; } }