001: /**********************************************************************************
002:
003: Feedzeo!
004: A free and open source RSS/Atom/RDF feed aggregator
005:
006: Copyright (C) 2005-2006 Anand Rao (anandrao@users.sourceforge.net)
007:
008: This library is free software; you can redistribute it and/or
009: modify it under the terms of the GNU Lesser General Public
010: License as published by the Free Software Foundation; either
011: version 2.1 of the License, or (at your option) any later version.
012:
013: This library is distributed in the hope that it will be useful,
014: but WITHOUT ANY WARRANTY; without even the implied warranty of
015: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
016: Lesser General Public License for more details.
017:
018: You should have received a copy of the GNU Lesser General Public
019: License along with this library; if not, write to the Free Software
020: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
021:
022: ************************************************************************************/package app;
023:
024: import java.net.*;
025: import java.io.*;
026: import java.util.*;
027:
028: import util.*;
029: import css.*;
030: import data.*;
031: import layout.*;
032:
033: import de.nava.informa.parsers.OPMLParser;
034: import de.nava.informa.impl.basic.Feed;
035:
036: /**
037: *
038: * @author Anand Rao
039: */
040: public class AppMain extends Thread implements AppCommandIF {
041:
042: private String FeedConfigFileName;
043: private String StyleInfoFileName;
044: private String LayoutFileName;
045: private String OutputPath;
046:
047: private LayoutManager LayoutMgr;
048: private DataManager DataMgr;
049: private StyleManager StyleMgr;
050:
051: private FeedInputFileParser fParser;
052:
053: private final int DEFAULT_REFRESHTIME = 30 * 60 * 1000; // 30 mins in millisecs
054: private final int MINIMUM_REFRESHTIME = 10 * 60 * 1000; // 10 mins
055:
056: private int refreshInterval = DEFAULT_REFRESHTIME;
057:
058: private final String styleFname = "style.css";
059:
060: /** Creates a new instance of AppMain */
061: public AppMain(String FeedConfigFileName, String StyleInfoFileName,
062: String LayoutFileName, String OutputPath) {
063: super ();
064: this .FeedConfigFileName = FeedConfigFileName;
065: this .StyleInfoFileName = StyleInfoFileName;
066: this .LayoutFileName = LayoutFileName;
067: this .OutputPath = OutputPath;
068: try {
069: fParser = new FeedInputFileParser(FeedConfigFileName);
070: } catch (Exception e) {
071: ExceptionUtil.reportException(e);
072: }
073: }
074:
075: /*****
076: // called during system exit
077: public void shutdown() {
078: // close the FeedInputFileParser
079: fParser.closeParser();
080: }
081: *****/
082:
083: private void sleepms(int ms) {
084: try {
085: sleep(ms);
086: } catch (Exception e) {
087: ExceptionUtil.reportException(e);
088: }
089: }
090:
091: private int DATAMGR_ADDLINK(String Categoryname, String Link) {
092: int retval;
093: retval = DataMgr.addLink(Categoryname, Link);
094: return retval;
095: }
096:
097: private int DATAMGR_DELLINK(String Categoryname, String Link) {
098: int retval;
099: retval = DataMgr.delLink(Categoryname, Link);
100: return retval;
101: }
102:
103: private String DATAMGR_GET_HTMLFILENAME(String Category, String Link) {
104: String retval;
105: retval = DataMgr.getChannelHTMLPageLink(Category, Link);
106: return retval;
107: }
108:
109: private String DATAMGR_GET_HTMLTABLEDATAFILENAME(String Category,
110: String Link) {
111: String retval;
112: retval = DataMgr
113: .getChannelHTMLTableDataPageLink(Category, Link);
114: return retval;
115: }
116:
117: /*
118: private int DATAMGR_GET_NUMCATEGORIES() {
119: int retval;
120: retval = DataMgr.getNumCategories();
121: return retval;
122: }
123:
124: */
125:
126: private Vector DATAMGR_GET_CATEGORYNAMES() {
127: Vector retval;
128: retval = DataMgr.getCategorynames();
129: return retval;
130: }
131:
132: private Vector DATAMGR_GET_FEEDNAMES(String Category) {
133: Vector retval;
134: retval = DataMgr.getFeedNames(Category);
135: return retval;
136: }
137:
138: private String DATAMGR_GET_FEEDNAME(String Category, String link) {
139: String retval;
140: retval = DataMgr.getFeedName(Category, link);
141: return retval;
142: }
143:
144: private String DATAMGR_GET_FEEDTABLEDATAPAGELINK(String Category,
145: String link) {
146: String retval;
147: retval = DataMgr.getFeedTableDataPageLink(Category, link);
148: return retval;
149: }
150:
151: private Vector DATAMGR_GET_ALLFEEDNAMES() {
152: Vector retval;
153: retval = DataMgr.getAllFeedNames();
154: return retval;
155: }
156:
157: private Vector DATAMGR_GET_FEEDPAGELINKS(String Category) {
158: Vector retval;
159: retval = DataMgr.getFeedPageLinks(Category);
160: return retval;
161: }
162:
163: private Vector DATAMGR_GET_FEEDSOURCELINKS(String Category) {
164: Vector retval;
165: retval = DataMgr.getFeedSourceLinks(Category);
166: return retval;
167: }
168:
169: private Vector DATAMGR_GET_ALLFEEDPAGELINKS() {
170: Vector retval;
171: retval = DataMgr.getAllFeedPageLinks();
172: return retval;
173: }
174:
175: private Vector DATAMGR_GET_FEEDTABLEDATAPAGELINKS(String Category) {
176: Vector retval;
177: retval = DataMgr.getFeedTableDataPageLinks(Category);
178: return retval;
179: }
180:
181: private Vector DATAMGR_GET_ALLFEEDTABLEDATAPAGELINKS() {
182: Vector retval;
183: retval = DataMgr.getAllFeedTableDataPageLinks();
184: return retval;
185: }
186:
187: private void DATAMGR_REFRESHCHANNEL(String Category,
188: String feedSourceLink) {
189: String HTMLFileName, HTMLTableDataFileName;
190: // copy the file names before refreshing the channel data
191: HTMLFileName = DataMgr.getChannelHTMLPageLink(Category,
192: feedSourceLink);
193: HTMLTableDataFileName = DataMgr
194: .getChannelHTMLTableDataPageLink(Category,
195: feedSourceLink);
196: if (DataMgr.refreshChannel(Category, feedSourceLink) < 0)
197: return; // no need to republish the html files
198: publishFeed(Category, feedSourceLink, HTMLFileName,
199: HTMLTableDataFileName);
200: }
201:
202: private void publishFeed(String Category, String feedSourceLink,
203: String HTMLFileName, String HTMLTableDataFileName) {
204: PageRequest req;
205:
206: /* generate the page for feed */
207: req = new PageRequest(Category, feedSourceLink, OutputPath,
208: HTMLFileName, HTMLTableDataFileName, LayoutMgr
209: .getMainPageLayoutName());
210: LayoutMgr.outputPage(req);
211: }
212:
213: private int generateFeed(String Categoryname, String Feedurl) {
214: // get a filename for the feed
215: String filename = FileNameGen.generateFileName();
216: String HTMLFileName = filename + ".html";
217: String HTMLTableDataFileName = filename + ".txt";
218:
219: /* add the link to datamgr */
220: if (DATAMGR_ADDLINK(Categoryname, Feedurl) < 0)
221: return -1;
222: publishFeed(Categoryname, Feedurl, HTMLFileName,
223: HTMLTableDataFileName);
224: return 0;
225: }
226:
227: private void generateFeedPages() {
228: int NumCats = 0;
229:
230: //System.out.println("Inside generateFeedPages");
231: FileNameGen.init(); // init the file name generator
232:
233: try {
234: NumCats = fParser.getNumCategories();
235: //System.out.println("Num of Categories:"+NumCats);
236:
237: for (int i = 0; i < NumCats; i++) {
238: String CatName, url;
239: Vector Feedurls;
240:
241: CatName = fParser.getCategory(i);
242: //System.out.println("Category#:"+CatName);
243:
244: Feedurls = fParser.getCategoryFeedsCollection(CatName);
245:
246: for (int j = 0; j < Feedurls.size(); j++) {
247: url = (String) Feedurls.elementAt(j);
248: //System.out.println("### ADD Cat:"+CatName+" Link:"+url);
249: generateFeed(CatName, url);
250: sleepms(5); /* sleep for 5ms to give the request handling threads
251: better response time */
252: }
253: }
254: } catch (Exception e) {
255: ExceptionUtil.reportException(e);
256: }
257: }
258:
259: private void refreshFeedData() {
260: String category, feedurl;
261: Vector categoryNames = DATAMGR_GET_CATEGORYNAMES();
262: if (categoryNames == null)
263: return;
264: for (int i = 0; i < categoryNames.size(); i++) {
265: category = (String) categoryNames.elementAt(i);
266: Vector feedSourceLinks = DATAMGR_GET_FEEDSOURCELINKS(category);
267: if (feedSourceLinks == null)
268: return;
269: for (int j = 0; j < feedSourceLinks.size(); j++) {
270: feedurl = (String) feedSourceLinks.elementAt(j);
271: DATAMGR_REFRESHCHANNEL(category, feedurl);
272: sleepms(5); /* sleep for 5ms to give the request handling threads
273: better response time */
274: }
275: }
276: }
277:
278: public void run() {
279: int runInterval = getRefreshInterval();
280:
281: System.out.println("THREAD refresh interval:" + runInterval);
282:
283: // Initialize StyleManager; generate the css file for the HTML files;
284: StyleMgr = new StyleManager(StyleInfoFileName);
285: StyleMgr.generateCSSFile(FileUtils.getFullFileName(OutputPath,
286: styleFname));
287: // Initialize the data manager
288: DataMgr = new DataManager();
289: SysObjects.setDataManager(DataMgr);
290: // Initialize the Layout manager
291: LayoutMgr = new LayoutManager();
292: SysObjects.setLayoutManager(LayoutMgr);
293: LayoutMgr.createFramework(LayoutFileName);
294: // Read through the feed config file and
295: // fetch each feed; for every feed fetched
296: // generate the corresponding HTML page
297: generateFeedPages();
298: while (true) {
299: sleepms(runInterval);
300: refreshFeedData();
301: }
302: }
303:
304: /* routines processing commands from the config server */
305: private CmdResult sendCategoryDataCmd() {
306: CmdResult cmdRes = null;
307: Vector result;
308:
309: result = DATAMGR_GET_CATEGORYNAMES();
310:
311: if (result != null)
312: cmdRes = new CmdResult(CmdResult.SUCESS_CODE, result);
313: else
314: cmdRes = new CmdResult(CmdResult.FAIL_CODE, null);
315: return cmdRes;
316: }
317:
318: /*
319: * does the function of addlink + also adds the url to the
320: * config file
321: */
322: private int addLinkPermanent(String Category, String LinkUrl) {
323: int rval = -1;
324:
325: rval = generateFeed(Category, LinkUrl);
326: if (rval < 0)
327: return rval;
328: // add the link into the config file
329: rval = fParser.insertFeedLink(Category, LinkUrl);
330: System.out.println("Added in category:" + Category + " link:"
331: + LinkUrl);
332: return rval;
333: }
334:
335: private CmdResult addLinkCmd(String Category, String link) {
336: // add link & generate pages
337: if (addLinkPermanent(Category, link) == 0) {
338: return new CmdResult(CmdResult.SUCESS_CODE, null);
339: }
340: return new CmdResult(CmdResult.FAIL_CODE, null);
341: }
342:
343: private CmdResult opmlImportCmd(String Category, String SourceURL) {
344:
345: Vector retVal = new Vector();
346: Collection feedCollection;
347: // first parse the opml file using informa api;
348: try {
349: feedCollection = OPMLParser.parse(SourceURL);
350: if (feedCollection == null)
351: return new CmdResult(CmdResult.FAIL_CODE, null);
352: } catch (Exception e) {
353: ExceptionUtil.reportException(e);
354: return new CmdResult(CmdResult.FAIL_CODE, null);
355: }
356: // we now have a collection of FeedIF objects;
357: Iterator i = feedCollection.iterator();
358: while (i.hasNext()) {
359: Feed f = (Feed) i.next();
360: // add this feed
361: CmdResult addResult = addLinkCmd(Category, f.getLocation()
362: .toString());
363: String resStr = "Feed " + f.getLocation().toString()
364: + " import";
365: if (addResult.getReturnCode() == CmdResult.SUCESS_CODE) {
366: System.out.println(resStr + " succeeded");
367: resStr += " succeeded\n";
368: } else {
369: System.out.println(resStr + " failed");
370: resStr += " failed\n";
371: }
372: retVal.addElement((String) resStr);
373: }
374:
375: return new CmdResult(CmdResult.SUCESS_CODE, retVal);
376:
377: }
378:
379: private CmdResult delLinkCmd(String Category, String link) {
380: /*
381: * 1. note down the feed html and data files generated for this feed
382: * 2. delete the feed in data manager
383: * 3. delete the feed html and data files
384: * 4. delete the feed url from the feedinputfile
385: */
386: String feedHTMLfile = DATAMGR_GET_HTMLFILENAME(Category, link), feedDatafile = DATAMGR_GET_HTMLTABLEDATAFILENAME(
387: Category, link);
388:
389: //System.out.println("deleting category:"+Category+" link:"+link);
390:
391: if (DATAMGR_DELLINK(Category, link) == 0) {
392:
393: //System.out.println("deleting file:"+feedHTMLfile);
394: FileUtils.deleteFile(FileUtils.getFullFileName(OutputPath,
395: feedHTMLfile));
396:
397: //System.out.println("deleting file:"+feedDatafile);
398: FileUtils.deleteFile(FileUtils.getFullFileName(OutputPath,
399: feedDatafile));
400: //System.out.println("deleting link from feedinputfile ...");
401: fParser.deleteFeedLink(Category, link);
402: return new CmdResult(CmdResult.SUCESS_CODE, null);
403: }
404: return new CmdResult(CmdResult.FAIL_CODE, null);
405: }
406:
407: private CmdResult sendFeedNamesCmd(String Category) {
408: Vector feednames = DATAMGR_GET_FEEDNAMES(Category);
409: if (feednames != null)
410: return new CmdResult(CmdResult.SUCESS_CODE, feednames);
411: return new CmdResult(CmdResult.FAIL_CODE, null);
412: }
413:
414: private CmdResult sendFeedNamesWithPageLinkCmd(String Category) {
415: Vector Result, feedNames, feedLinks;
416: Result = new Vector();
417:
418: if (Category != null) {
419: feedNames = DATAMGR_GET_FEEDNAMES(Category);
420: feedLinks = DATAMGR_GET_FEEDPAGELINKS(Category);
421: } else {
422: feedNames = DATAMGR_GET_ALLFEEDNAMES();
423: feedLinks = DATAMGR_GET_ALLFEEDPAGELINKS();
424: }
425:
426: if ((feedNames == null) || (feedLinks == null))
427: return new CmdResult(CmdResult.FAIL_CODE, null);
428:
429: for (int i = 0; i < feedNames.size(); i++) {
430: String feedlinkStr = new String(feedNames.elementAt(i)
431: + "\t" + feedLinks.elementAt(i));
432: Result.addElement(feedlinkStr);
433: //System.out.println("RESULT: "+ feedlinkStr);
434: }
435: if (Result != null)
436: return new CmdResult(CmdResult.SUCESS_CODE, Result);
437: return new CmdResult(CmdResult.FAIL_CODE, null);
438: }
439:
440: private CmdResult sendFeedNamesWithTableDataPageLinkCmd(
441: String Category) {
442: Vector Result, feedNames, feedLinks;
443: Result = new Vector();
444:
445: if (Category != null) {
446: feedNames = DATAMGR_GET_FEEDNAMES(Category);
447: feedLinks = DATAMGR_GET_FEEDTABLEDATAPAGELINKS(Category);
448: } else {
449: feedNames = DATAMGR_GET_ALLFEEDNAMES();
450: feedLinks = DATAMGR_GET_ALLFEEDTABLEDATAPAGELINKS();
451: }
452:
453: if ((feedNames == null) || (feedLinks == null))
454: return new CmdResult(CmdResult.FAIL_CODE, null);
455:
456: for (int i = 0; i < feedNames.size(); i++) {
457: String feedlinkStr = new String(feedNames.elementAt(i)
458: + "\t" + feedLinks.elementAt(i));
459: Result.addElement(feedlinkStr);
460: //System.out.println("RESULT: "+ feedlinkStr);
461: }
462: if (Result != null)
463: return new CmdResult(CmdResult.SUCESS_CODE, Result);
464: return new CmdResult(CmdResult.FAIL_CODE, null);
465: }
466:
467: private CmdResult sendFeedNamesWithFeedSourceLinkCmd(String Category) {
468: Vector Result, feedNames, feedSourceLinks;
469: Result = new Vector();
470:
471: if (Category != null) {
472: feedNames = DATAMGR_GET_FEEDNAMES(Category);
473: feedSourceLinks = DATAMGR_GET_FEEDSOURCELINKS(Category);
474:
475: if ((feedNames == null) || (feedSourceLinks == null))
476: return new CmdResult(CmdResult.FAIL_CODE, null);
477:
478: for (int i = 0; i < feedNames.size(); i++) {
479: String feedlinkStr = new String(feedNames.elementAt(i)
480: + "\t" + feedSourceLinks.elementAt(i));
481: Result.addElement(feedlinkStr);
482: //System.out.println("APPMAIN RESULT: "+ feedlinkStr);
483: }
484: if (Result != null)
485: return new CmdResult(CmdResult.SUCESS_CODE, Result);
486: }
487: return new CmdResult(CmdResult.FAIL_CODE, null);
488: }
489:
490: private CmdResult sendStyleInfoCmd() {
491: String str = StyleMgr.getStyleInfo();
492: if (str != null) {
493: Vector v = new Vector();
494: v.addElement(str);
495: return new CmdResult(CmdResult.SUCESS_CODE, v);
496: }
497: return new CmdResult(CmdResult.FAIL_CODE, null);
498: }
499:
500: private CmdResult saveStyleInfoCmd(String filedata) {
501: int result = StyleMgr.saveStyleInfo(filedata);
502: if (result < 0)
503: return new CmdResult(CmdResult.FAIL_CODE, null);
504: StyleMgr.generateCSSFile(FileUtils.getFullFileName(OutputPath,
505: styleFname));
506: return new CmdResult(CmdResult.SUCESS_CODE, null);
507: }
508:
509: private CmdResult sendFeedNamesWithTblDataPgLinkFromSourceURLCmd(
510: String Category, String feedSourceURL) {
511: Vector Result;
512: String feedName, feedLink;
513: Result = new Vector();
514:
515: if ((Category == null) || (feedSourceURL == null))
516: return new CmdResult(CmdResult.FAIL_CODE, null);
517:
518: feedName = DATAMGR_GET_FEEDNAME(Category, feedSourceURL);
519: feedLink = DATAMGR_GET_FEEDTABLEDATAPAGELINK(Category,
520: feedSourceURL);
521:
522: if ((feedName != null) && (feedLink != null)) {
523: String feedlinkStr = new String(feedName + "\t" + feedLink);
524: Result.addElement(feedlinkStr);
525: return new CmdResult(CmdResult.SUCESS_CODE, Result);
526: }
527: return new CmdResult(CmdResult.FAIL_CODE, null);
528:
529: }
530:
531: /* The main Application API handler */
532:
533: public CmdResult handleCommand(Vector CmdInfo) {
534:
535: CmdResult res = null;
536: String data1 = null, data2 = null;
537:
538: int code = ((Integer) CmdInfo.elementAt(0)).intValue();
539: System.out.print("handleCommand: code=" + code + " ");
540:
541: /* for debug
542: for (int i = 1; i < CmdInfo.size(); i++)
543: System.out.println((String)CmdInfo.elementAt(i));
544: */
545:
546: // set up the arguments passed
547: if (CmdInfo.size() >= 2) {
548: data1 = (String) CmdInfo.elementAt(1);
549: if (CmdInfo.size() >= 3)
550: data2 = (String) CmdInfo.elementAt(2);
551: }
552:
553: switch (code) {
554: case AppCmd.GET_CATEGORIES:
555: res = sendCategoryDataCmd();
556: break;
557: case AppCmd.ADD_LINK:
558: res = addLinkCmd(data1, data2);
559: break;
560: case AppCmd.OPML_IMPORT:
561: res = opmlImportCmd(data1, data2);
562: break;
563: case AppCmd.GET_FEEDNAMES:
564: res = sendFeedNamesCmd(data1);
565: break;
566: case AppCmd.GET_FEEDNAMES_W_PAGE_LINK:
567: res = sendFeedNamesWithPageLinkCmd(data1);
568: break;
569: case AppCmd.GET_ALL_FEEDNAMES_W_PAGE_LINK:
570: res = sendFeedNamesWithPageLinkCmd(null);
571: break;
572: case AppCmd.GET_FEEDNAMES_W_TABLEDATA_PAGE_LINK:
573: res = sendFeedNamesWithTableDataPageLinkCmd(data1);
574: break;
575: case AppCmd.GET_ALL_FEEDNAMES_W_TABLEDATA_PAGE_LINK:
576: res = sendFeedNamesWithTableDataPageLinkCmd(null);
577: break;
578:
579: case AppCmd.GET_STYLE_INFO:
580: res = sendStyleInfoCmd();
581: break;
582: case AppCmd.SAVE_STYLE_INFO:
583: res = saveStyleInfoCmd(data1);
584: break;
585: case AppCmd.GET_FEEDNAMES_W_FEEDSOURCE_LINK:
586: res = sendFeedNamesWithFeedSourceLinkCmd(data1);
587: break;
588: case AppCmd.DEL_LINK:
589: res = delLinkCmd(data1, data2);
590: break;
591: case AppCmd.GET_FEEDNAMES_W_TABLEDATA_PAGE_LINK_FRM_SOURCEURL:
592: res = sendFeedNamesWithTblDataPgLinkFromSourceURLCmd(data1,
593: data2);
594: break;
595:
596: default:
597: break;
598: }
599: return res;
600: }
601:
602: public int getRefreshInterval() {
603: return refreshInterval;
604: }
605:
606: public void setRefreshInterval(int InMins) {
607: if (InMins < (MINIMUM_REFRESHTIME / (60 * 1000))) {
608: System.out
609: .println("Refresh time less than min refresh time of "
610: + MINIMUM_REFRESHTIME + " mins");
611: System.out.println("Setting refresh interval to "
612: + MINIMUM_REFRESHTIME + " mins");
613: InMins = MINIMUM_REFRESHTIME;
614: }
615: refreshInterval = InMins * 60 * 1000;
616: }
617:
618: }
|