/* * Created on 22.10.2003 */ package com.idega.block.rss.business; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; import com.idega.block.rss.data.RSSHeadline; import com.idega.block.rss.data.RSSHeadlineHome; import com.idega.block.rss.data.RSSHeadlineHomeImpl; import com.idega.block.rss.data.RSSSource; import com.idega.block.rss.data.RSSSourceHome; import com.idega.block.rss.data.RSSSourceHomeImpl; import com.idega.idegaweb.IWApplicationContext; import com.idega.idegaweb.IWBundle; import com.idega.idegaweb.IWBundleStartable; import com.idega.util.timer.PastDateException; import com.idega.util.timer.TimerEntry; import com.idega.util.timer.TimerListener; import com.idega.util.timer.TimerManager; /** * This bundle starter goes through all defined RSSSources, and updates the RSSHeadlines for them. * It is of course started when the server starts and runs at specific intervals. * * @author <a href="mailto:jonas@idega.is>Jonas K. Blandon</a> */ public class RSSBusinessPoller implements IWBundleStartable { private static String IW_BUNDLE_IDENTIFIER = "com.idega.block.rss"; /** * Gets an instance of RSSBusinessPoller * @return An instance of RSSBusinessPoller */ public static RSSBusinessPoller getInstance(IWApplicationContext iwac) { if(_instance == null){ (new RSSBusinessPoller()).start(iwac.getIWMainApplication().getBundle(IW_BUNDLE_IDENTIFIER)); } return _instance; } /** * Goes through all defined RSSSources, and updates the RSSHeadlines for them. * Removes RSSHeadlines that are no longer present in the RSSSource from the * server. This means that the RSSHeadlines in the database are a time snapshot * of the response from the RSSSource server. * */ private void updateAllRSSHeadlines() { try { RSSSourceHome sHome = new RSSSourceHomeImpl(); Collection sources = sHome.findSources(); Iterator sIter = sources.iterator(); while(sIter.hasNext()) { RSSSource source = (RSSSource)sIter.next(); System.out.println("Updating RSS Headlines for " + source); updateRSSHeadlinesForRSSSource(source); } } catch(Exception e) { e.printStackTrace(); } } /** * Brings all RSSHeadlines for a given RSSSource up to date * @param rssSource The RSSSource to bring headlines up to date for * @return true if headlines are up to date, false otherwise (if, for * example, the no rss response was retrieved from the url) */ public boolean updateRSSHeadlinesForRSSSource(RSSSource rssSource) { //String sourceUrl = rssSource.getSourceURL(); //String sourceId = rssSource.getSourceId(); System.out.println("Saving snapshot of rss source " + rssSource); try { Collection newHeadlines = getLatestHeadlinesFromRSSByRSSSource(rssSource); if(newHeadlines.isEmpty()) { return false; } RSSBusiness business = getBusiness(); Collection oldHeadlines = business.getHeadlinesByRSSSource(rssSource); Iterator newHeadlineIter = newHeadlines.iterator(); if(newHeadlineIter.hasNext()) { while (newHeadlineIter.hasNext()) { try{ RSSHeadline headline = (RSSHeadline) newHeadlineIter.next(); if(oldHeadlines.contains(headline)) { // headline already exists, don't reinsert and don't remove later System.out.println("Headline from rss already exists: " + headline); oldHeadlines.remove(headline); } else { System.out.println("Inserting new Headline from rss: " + headline); headline.store(); rssSource.addHeadline(headline); } } catch(Exception e){ System.out.println("Exception inserting headline"); e.printStackTrace(); } } } // now go through the remaining headlines in existingHeadlines (they are the // ones that no longer exists in the rss response) and remove them Iterator oldHeadlineIter = oldHeadlines.iterator(); if(oldHeadlineIter.hasNext()) { while (oldHeadlineIter.hasNext()) { try { RSSHeadline headline = (RSSHeadline) oldHeadlineIter.next(); if(!newHeadlines.contains(headline)) { System.out.println("Removing headline no longer in rss (" + headline +")"); headline.remove(); } } catch(Exception e){ System.out.println("Exception removing headline"); e.printStackTrace(); } } } return true; } catch (Exception e) { e.printStackTrace(); return false; } } /** * Retrieves the latest RSSHeadlines for a given RSSSource by making a * request to the RSS server. Note: The headlines in the list have not * been stored persistently. * @param rssSource The RSSSource to retrieve latest RSSHeadline from * @return A List of latest RSSHeadlines */ public List getLatestHeadlinesFromRSSByRSSSource(RSSSource rssSource) { SAXBuilder builder = new SAXBuilder(); ArrayList theReturn = new ArrayList(); try { URL url = new URL(rssSource.getSourceURL()); Document doc = builder.build(url); ArrayList items = new ArrayList(8); collectItems(doc.getRootElement(), items); int numItems = items.size(); for(int i=0; i<numItems; i++) { Element item = (Element) items.get(i); Element eTitle = item.getChild("title", item.getNamespace()); Element eLink = item.getChild("link", item.getNamespace()); if(eTitle==null || eLink==null) { continue; } String sTitle = eTitle.getText(); String sLink = eLink.getText(); if(sTitle==null || sLink==null) { continue; } RSSHeadlineHome hHome = new RSSHeadlineHomeImpl(); RSSHeadline h = hHome.create(); h.setHeadline(sTitle); h.setLink(sLink); theReturn.add(h); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (Exception e) { //String msg = e.getMessage(); e.printStackTrace(); } return theReturn; } /** * Collects all elements with name "item" below an element into a collection * @param element search this element and its descendants * @param col The collection to add "item" elements into */ private void collectItems(Element element, List col) { if("item".equals(element.getName())) { col.add(element); } java.util.List children = element.getChildren(); Iterator iter = children.iterator(); while (iter.hasNext()) { Element item = (Element) iter.next(); collectItems(item, col); } } /* (non-Javadoc) * @see com.idega.idegaweb.IWBundleStartable#start(com.idega.idegaweb.IWBundle) */ public void start(IWBundle starterBundle) { String strPollInterval = starterBundle.getProperty(BUNDLE_PROPERTY_NAME_POLL_INTERVAL); if(strPollInterval!=null && strPollInterval.length()>0) { try { pollInterval = Integer.parseInt(strPollInterval.trim()); System.out.println("Poll interval set to " + pollInterval + " minutes"); } catch(NumberFormatException e) { System.out.println("Could not set rss poll interval to " + strPollInterval); e.printStackTrace(); } } _instance = this; this.bundle_ = starterBundle; if (tManager==null) { tManager = new TimerManager(); } if(pollTimerEntry==null) { try { pollTimerEntry = tManager.addTimer(pollInterval, true, new TimerListener() { public void handleTimer(TimerEntry entry) { updateAllRSSHeadlines(); } }); } catch(PastDateException e) { pollTimerEntry = null; e.printStackTrace(); } } } /* (non-Javadoc) * @see com.idega.idegaweb.IWBundleStartable#stop(com.idega.idegaweb.IWBundle) */ public void stop(IWBundle starterBundle) { if(tManager!=null) { if (pollTimerEntry != null) { tManager.removeTimer(pollTimerEntry); pollTimerEntry = null; } } } /** * Gets an instance of RSSBusiness * @return An instance of RSSBusiness */ private RSSBusiness getBusiness() { if(this._business==null) { try { RSSBusinessHome businessHome = new RSSBusinessHomeImpl(); this._business = businessHome.create(); } catch(Exception e) { e.printStackTrace(); } } return this._business; } private RSSBusiness _business = null; private static int pollInterval = 30; // polling interval in minutes private static TimerManager tManager = null; private static TimerEntry pollTimerEntry = null; private static RSSBusinessPoller _instance = null; private static final String BUNDLE_PROPERTY_NAME_POLL_INTERVAL = "iw_bundle_rss_poll_interval"; private IWBundle bundle_; }