Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/fm/rss/rssChannel.java


1   /****************************************************************************
2    * Copyright (c) 2003 Andrew Duka | aduka@users.sourceforge.net
3    * All right reserved.
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU Lesser General Public
7    * License as published by the Free Software Foundation; either
8    * version 2.1 of the License, or (at your option) any later version.
9    *
10   ****************************************************************************/
11  package com.fm.rss;
12  
13  import java.util.*;
14  
15  import org.w3c.dom.*;
16  import com.fm.update.Updateable;
17  import com.fm.update.updateException;
18  import com.fm.rss.filter.RssItemFilter;
19  import com.fm.rss.filter.rssFilterFactory;
20  
21  import javax.xml.parsers.ParserConfigurationException;
22  
23  /**
24   * Entities of the class represent RSS channels.
25   *
26   * @author Andrew Duka (Andrew.Duka@oktet.ru)
27   */
28  public class rssChannel extends rssAbstractEntry implements ItemContainer, Updateable
29  {
30      private HashMap   itemList;         /** array of the channels items            */
31  
32      private String    link;             /** channel parent URI                     */
33      private String    source;           /** channel RSS feed source URI            */
34      private String    creator;          /** channel source URI                     */
35  
36      private String    language;         /** channel source URI                     */
37      private int       ttl;              /** number of minutes a channel may be cached */
38      private String    imageTitle;       /** image title if image element is present,
39                                              empty string otherwise */
40      private String    imageURL;
41      private String    imageLink;
42  
43      private int       keepPeriod;       /** number of days item may be stored.
44                                              if item is older than keepPeriod days it wont
45                                              be loaded or saved */
46  
47      private boolean   isUpdateOperation;
48  
49      public static int MAX_KEEP_PERIOD = Integer.MAX_VALUE; /** enough days for human history */
50  
51  
52      public rssChannel()
53      {
54          title = "";
55          description = "";
56          dateCreated = new Date();
57          idHash = 0;
58          creator = "";
59          link = "";
60          language = "en-us";
61          source = "";
62          itemList = new HashMap();
63          imageLink = "";
64          imageTitle = "";
65          imageURL = "";
66          ttl  = -1;
67          isUpdateOperation = false;
68          keepPeriod = rssChannel.MAX_KEEP_PERIOD;
69      }
70  
71  
72      /**
73       * Returns channel as XML document element
74       *
75       * @return DOM Element object with representation of the item container
76       */
77      public Element toDomElement()
78      {
79          Element root_elem;
80          Element temp;
81          Element sub_entry = null;
82  
83          if (this.docAdapter == null)
84          {
85              try
86              {
87                  docAdapter = documentAdapter.newInstance();
88              }
89              catch (ParserConfigurationException pce)
90              {
91                  //catch exception here
92                  pce.printStackTrace();
93                  return null;
94              }
95          }
96  
97          root_elem = this.docAdapter.createElement("rss-channel");
98  
99          try
100         {
101             // ID & Version
102             root_elem.setAttribute("id", Integer.toString(this.getID()));
103             root_elem.setAttribute("version", "1.0");
104             //  Title, Description, dateCreated
105             temp = this.docAdapter.createElement("title", "dc",
106                                                  documentAdapter.DC_NAMESPACE_URI);
107             temp.appendChild(this.docAdapter.createTextNode(getTitle()));
108             root_elem.appendChild(temp);
109 
110             temp = this.docAdapter.createElement("description", "dc",
111                                                  documentAdapter.DC_NAMESPACE_URI);
112 
113             String descr = getDescription();
114             temp.appendChild(this.docAdapter.createTextNode(descr));
115             root_elem.appendChild(temp);
116 
117             temp = this.docAdapter.createElement("source", "dc",
118                                                  documentAdapter.DC_NAMESPACE_URI);
119             temp.appendChild(this.docAdapter.createTextNode(this.getSource()));
120             root_elem.appendChild(temp);
121 
122 
123             temp = this.docAdapter.createElement("dateCreated");
124             temp.appendChild(this.docAdapter.
125                                   createTextNode(rssDateHandler.
126                                                     dateToString(getDateCreated(),
127                                                                  rssDateHandler.RSS_OUTPUT_PATTERN)));
128             root_elem.appendChild(temp);
129 
130             temp = this.docAdapter.createElement("language", "dc",
131                                                  documentAdapter.DCTERMS_NAMESPACE_URI);
132             temp.appendChild(this.docAdapter.createTextNode(this.getLanguage()));
133             root_elem.appendChild(temp);
134 
135 
136             temp = this.docAdapter.createElement("creator", "dc",
137                                                  documentAdapter.DC_NAMESPACE_URI);
138             temp.appendChild(this.docAdapter.createTextNode(this.getCreator()));
139             root_elem.appendChild(temp);
140 
141             temp = this.docAdapter.createElement("link");
142             temp.appendChild(this.docAdapter.createTextNode(this.getLink()));
143             root_elem.appendChild(temp);
144 
145             temp = this.docAdapter.createElement("keepPeriod");
146             temp.appendChild(this.docAdapter.createTextNode((new Integer(this.getKeepPeriod())).toString()));
147             root_elem.appendChild(temp);
148 
149             //have image assoicated
150             if (this.imageURL.length() > 0)
151             {
152                 temp = this.docAdapter.createElement("image");
153                 Element i_tel = this.docAdapter.createElement("url");
154                 i_tel.appendChild(this.docAdapter.createTextNode(this.getImageURL()));
155                 temp.appendChild(i_tel);
156 
157                 if (this.imageTitle.length() > 0)
158                 {
159                    i_tel = this.docAdapter.createElement("title");
160                    i_tel.appendChild(this.docAdapter.createTextNode(this.getImageTitle()));
161                    temp.appendChild(i_tel);
162                 }
163 
164                 if (this.imageLink.length() > 0)
165                 {
166                    i_tel = this.docAdapter.createElement("link");
167                    i_tel.appendChild(this.docAdapter.createTextNode(this.getImageLink()));
168                    temp.appendChild(i_tel);
169                 }
170                 root_elem.appendChild(temp);
171             }
172 
173             // have ttl
174             if (this.ttl > 0)
175             {
176                 temp = this.docAdapter.createElement("ttl");
177                 temp.appendChild(this.docAdapter.createTextNode(Integer.toString(this.ttl)));
178                 root_elem.appendChild(temp);
179             }
180             //System.out.println("ROOT: " + root_elem.toString());
181 
182             // dumping channel items
183             synchronized (itemList)
184             {
185                 if (keepPeriod != 0)
186                 {
187                     Vector v = getItemVector();
188 
189                     if (keepPeriod < MAX_KEEP_PERIOD)
190                     {
191                         Calendar c = Calendar.getInstance();
192                         int day = c.get(Calendar.DAY_OF_YEAR) - keepPeriod;
193                         c.set(Calendar.DAY_OF_YEAR, day);
194                         RssItemFilter f = rssFilterFactory.createDateFilter(c.getTime());
195                         v = f.filter(v);
196                     }
197 
198                     for (Iterator i = v.iterator(); i.hasNext();)
199                     {
200                         sub_entry = ((rssAbstractEntry)i.next()).toDomElement();
201                         if (sub_entry != null)
202                         {
203                             root_elem.appendChild(sub_entry);
204                         }
205                         else
206                         {
207                             //possibly report error here
208                         }
209                     }
210                 }
211             }
212         }
213         catch (DOMException e)
214         {
215             e.printStackTrace();
216             return null;
217         }
218 
219         return root_elem;
220     }
221 
222 
223     /**
224      * Update channel items. This method will connect to the server,
225      * retreive RSS feed and aggregate new items (items which have been
226      * published after last time this method had been called).
227      *
228      * @throws com.fm.update.updateException if error occured during update
229      */
230     public void update() throws updateException
231     {
232         isUpdateOperation = true;
233 
234         try
235         {
236             parse(getSource());
237             isUpdateOperation = false;  // restoring
238         }
239         catch (rssParseException e)
240         {
241             isUpdateOperation = false;  // restoring
242             throw new updateException(e.toString());
243         }
244     }
245 
246 
247     /**
248      * Returns Map of the channel items.
249      *
250      * @return ArrayList object with the channel items
251      */
252     public Map getItems()
253     {
254         return itemList;
255     }
256 
257     /**
258      * Return Vector of the items
259      *
260      * Items are unsorted and if user wants the sorted list, the sorting filter
261      * should be applied. The items in the list may be sorted naturally, due to
262      * extraction order (items appear in the list as they appear in the channel),
263      * but such implementation nuances mustn't be taken seriously.
264      *
265      * @return
266      */
267     public Vector getItemVector()
268     {
269         return new Vector(itemList.values());
270     }
271 
272     /**
273      * Replaces the channel's item list with given one.
274      *
275      * @param newIMap new Map with the items
276      *
277      */
278     public void setItemList(Map newIMap)
279     {
280         itemList = new HashMap(newIMap);
281     }
282 
283 
284     /**
285      * Parse given Element object and initialize channel params and item list.
286      *
287      * <p>As soon as there are more than one description format for RSS channels,
288      * the parse method actually does only simple checks for description format
289      * and then forwards given Element object to the appropriate private method.
290      * The three major description formats are: RSSv1, RSSv2 (by Userland), JNR
291      * (internal format based on DublinCore elements, which intended for the
292      * local storing of the channels,categories and items data). Since RSSv2
293      * backward compatible with 0.9x formats, the channels described using 0.9x
294      * format will be handled with <code>parseRSSv2()</code>.</p>
295      *
296      * @param el
297      * @throws com.fm.rss.rssParseException
298      */
299     public synchronized void parse(Element el) throws rssParseException
300     {
301         String el_t = el.getNodeName();
302 
303         if (el_t.equalsIgnoreCase("rdf:RDF")) // RSS1
304         {
305             try
306             {
307                 this.parseRSSv1(el);
308             }
309             catch (rssParseException pe)
310             {
311           pe.printStackTrace();
312                 throw new rssParseException("RSSv1 parse exception: " + pe.toString());
313             }
314         }
315         else if (el_t.equalsIgnoreCase("rss-channel")) // JNR
316         {
317             try
318             {
319                 this.parseJNRFormat(el);
320             }
321             catch (rssParseException pe)
322             {
323                 throw new rssParseException("JNR format parse exception: " + pe.toString());
324             }
325         }
326         else if (el_t.equalsIgnoreCase("rss")) // JNR
327         {
328             try
329             {
330                 this.parseRSSv2(el);
331             }
332             catch (rssParseException pe)
333             {
334                 throw new rssParseException("RSS format parse exception: " + pe.toString());
335             }
336         }
337     }
338 
339     /**
340      * Parse element object representing RSS channel encoded using RSS v1
341      * specification
342      *
343      * @param el Element object
344      * @throws com.fm.rss.rssParseException
345      */
346     private void parseRSSv1(Element el) throws rssParseException
347     {
348         Node curr_node;
349         Node temp;   /* All optional elements may return null as a value,
350                        so we need temporal string to check this out   */
351 
352         NodeList t_nl = el.getElementsByTagName("channel");
353 
354         if (t_nl.getLength() == 0)
355         {
356             throw new rssParseException("RSS channel: invalid RSS1 channel spec - channel element is absent");
357         }
358 
359         String node_name;
360         NodeList nl = (t_nl.item(0)).getChildNodes();
361         int child_num = nl.getLength();
362 
363         for (int i=0; i < child_num; i++)
364         {
365             curr_node = nl.item(i);
366 
367             if (curr_node.getNodeType() == Node.ELEMENT_NODE)
368             {
369                 node_name = curr_node.getNodeName();
370                 if (node_name.equalsIgnoreCase("title"))
371                 {
372                     if ((temp = curr_node.getFirstChild()) != null)
373                        this.setTitle(temp.getNodeValue());
374                     else
375                        this.setTitle("");
376                 }
377                 else if (node_name.equalsIgnoreCase("description"))
378                 {
379                     if ((temp = curr_node.getFirstChild()) != null)
380                        this.setDescription(temp.getNodeValue());
381                     else
382                        this.setDescription("");
383                 }
384                 else if (node_name.equalsIgnoreCase("dc:date"))
385                 {
386                     if ((temp = curr_node.getFirstChild()) != null)
387                        setDateCreated(rssDateHandler.getDateInstanceFromDC(temp.getNodeValue()));
388                 }
389                 else if (node_name.equalsIgnoreCase("dc:creator"))
390                 {
391                     if ((temp = curr_node.getFirstChild()) != null)
392                        this.setCreator(temp.getNodeValue());
393                     else
394                        this.setCreator("");
395                 }
396                 else if (node_name.equalsIgnoreCase("link"))
397                 {
398                     if ((temp = curr_node.getFirstChild()) != null)
399                        this.setLink(temp.getNodeValue());
400                     else
401                        throw new rssParseException("RSS channel: link element contains no data");
402                 }
403                 else if (node_name.equalsIgnoreCase("dc:language"))
404                 {
405                     if ((temp = curr_node.getFirstChild()) != null)
406                         this.setLanguage(temp.getNodeValue());
407                     else
408                         this.setLanguage("en-us");  // default value
409                 }
410             }//end of ELEMENT_NODE
411         }//end of for
412 
413         //IMAGE
414         nl  = el.getElementsByTagName("image");
415         child_num = nl.getLength();
416         for (int i=0; i < child_num; i++)
417         {
418             curr_node = nl.item(i);
419 
420             // we need only complete image description on nothing at all
421             if (curr_node.getParentNode() != el)
422             {
423                 continue;
424             }
425 
426             NamedNodeMap atts = curr_node.getAttributes();
427             Node t_node;
428             boolean isNoAbout = true;
429 
430             if ((atts != null) && ((t_node = atts.getNamedItem("rdf:about")) != null))
431             {
432                 this.setImageURL(t_node.getNodeValue());
433                 isNoAbout = false;
434             }
435 
436             NodeList t_ls = curr_node.getChildNodes();
437             String t_name;
438 
439             for (int t_i = 0; t_i < t_ls.getLength(); t_i++)
440             {
441                 t_node = t_ls.item(t_i);
442 
443                 if (t_node.getNodeType() == Node.ELEMENT_NODE)
444                 {
445                     //no parse exceptions, only known values will be set
446                     //image url is set using about attribute
447                     t_name = curr_node.getNodeName();
448                     if (t_name.equalsIgnoreCase("title"))
449                     {
450                         if ((temp = t_node.getFirstChild()) != null)
451                             this.setImageTitle(temp.getNodeValue());
452                     }
453                     if (t_name.equalsIgnoreCase("link") && (isNoAbout == true))
454                     {
455                         if ((temp = t_node.getFirstChild()) != null)
456                         {
457                             this.setImageLink(temp.getNodeValue());
458                             isNoAbout = false;
459                         }
460                     }
461                 }
462             }
463             if (isNoAbout)
464             {
465                 // possibly should be removed, because image element is optional
466                 throw new rssParseException("RSS v1 parse error: image source isn't specified");
467             }
468 
469         }
470 
471         // ITEMS
472         nl = el.getElementsByTagName("item");
473         child_num = nl.getLength();
474         rssItem new_i;
475 
476         for (int i=0; i < child_num; i++)
477         {
478             curr_node = nl.item(i);
479             new_i = new rssItem();
480 
481             try
482             {
483                 new_i.parse((Element)curr_node);
484                 new_i.setID(new_i.generateID());
485             }
486             catch (rssParseException pe)
487             {
488                 throw new rssParseException("rssChannel parse error: "+ pe.toString());
489             }
490 
491             this.addItem(new_i);
492             //System.out.println("Item description: " + new_i.getDescription());
493 
494         }//end of for
495     }
496 
497     /**
498      * Parse element object representing RSS channels in RSSv2 (and >= 0.91) format.
499      *
500      * @param el Element object
501      * @throws com.fm.rss.rssParseException
502      */
503     private void parseRSSv2(Element el) throws rssParseException
504     {
505         Node curr_node;
506         Node temp;   /* All optional elements may return null as a value,
507                        so we need temporal string to check this out   */
508 
509         NodeList t_nl = el.getElementsByTagName("channel");
510 
511         if (t_nl.getLength() == 0)
512         {
513             throw new rssParseException("RSS channel: invalid RSS2 channel spec - channel element is absent");
514         }
515 
516         String node_name;
517         rssItem new_i;
518         NodeList nl = (t_nl.item(0)).getChildNodes();
519         int child_num = nl.getLength();
520 
521         for (int i=0; i < child_num; i++)
522         {
523             curr_node = nl.item(i);
524 
525             if (curr_node.getNodeType() == Node.ELEMENT_NODE)
526             {
527                 node_name = curr_node.getNodeName();
528                 if (node_name.equalsIgnoreCase("title"))
529                 {
530                     if ((temp = curr_node.getFirstChild()) != null)
531                        this.setTitle(temp.getNodeValue());
532                     else
533                        this.setTitle("");
534                 }
535                 else if (node_name.equalsIgnoreCase("description"))
536                 {
537                     if ((temp = curr_node.getFirstChild()) != null)
538                        this.setDescription(temp.getNodeValue());
539                     else
540                        this.setDescription("");
541                 }
542                 else if (node_name.equalsIgnoreCase("link"))
543                 {
544                     if ((temp = curr_node.getFirstChild()) != null)
545                        this.setLink(temp.getNodeValue());
546                     else
547                        throw new rssParseException("RSS channel: link element contains no data");
548                 }
549                 else if (node_name.equalsIgnoreCase("pubDate"))
550                 {
551                     if ((temp = curr_node.getFirstChild()) != null)
552                        setDateCreated(rssDateHandler.getDateInstanceFromRSS(temp.getNodeValue()));
553                 }
554                 else if (node_name.equalsIgnoreCase("managingEditor"))
555                 {
556                     if ((temp = curr_node.getFirstChild()) != null)
557                        this.setCreator(temp.getNodeValue());
558                     else
559                        this.setCreator("");
560                 }
561                 else if (node_name.equalsIgnoreCase("image")) //we've got image
562                 {
563                     Node t_node;
564                     NodeList t_ls = curr_node.getChildNodes();
565                     String t_name;
566 
567                     for (int t_i = 0; t_i < t_ls.getLength(); t_i++)
568                     {
569                         t_node = t_ls.item(t_i);
570 
571                         if (t_node.getNodeType() == Node.ELEMENT_NODE)
572                         {
573                             //no parse exceptions, only known values will be set
574                             //image url is set using about attribute
575                             t_name = curr_node.getNodeName();
576                             if (t_name.equalsIgnoreCase("title"))
577                             {
578                                 if ((temp = t_node.getFirstChild()) != null)
579                                     this.setImageTitle(temp.getNodeValue());
580                             }
581                             if (t_name.equalsIgnoreCase("link"))
582                             {
583                                 if ((temp = t_node.getFirstChild()) != null)
584                                     this.setImageLink(temp.getNodeValue());
585                             }
586                             if (t_name.equalsIgnoreCase("url"))
587                             {
588                                 if ((temp = t_node.getFirstChild()) != null)
589                                     this.setImageURL(temp.getNodeValue());
590                             }
591                         }
592                     }
593                 }
594                 else if (node_name.equalsIgnoreCase("language"))
595                 {
596                     if ((temp = curr_node.getFirstChild()) != null)
597                         this.setLanguage(temp.getNodeValue());
598                     else
599                         this.setLanguage("en-us");  // default value
600                 }
601                 else if (node_name.equalsIgnoreCase("item"))
602                 {
603                     new_i = new rssItem();
604                     try
605                     {
606                         new_i.parse((Element)curr_node);
607                         new_i.setID(new_i.generateID());
608                     }
609                     catch (rssParseException pe)
610                     {
611                         throw new rssParseException("rssChannel parse error: "+ pe.toString());
612                     }
613 
614                     this.addItem(new_i);
615                 }
616             }//end of ELEMENT_NODE
617         }//end of for
618     }
619 
620     /**
621      * Parse element object representing RSS channel encoded using RSS v1
622      * specification
623      *
624      * @param el Element object
625      * @throws com.fm.rss.rssParseException
626      */
627     private void parseJNRFormat(Element el) throws rssParseException
628     {
629         Node curr_node;
630         Node temp;
631         NodeList nl = el.getChildNodes();
632         String node_name;
633         rssItem new_i;
634         int child_num = nl.getLength();
635 
636         Attr id_attr = el.getAttributeNode("id");
637         String idstr;
638         if ((id_attr == null) || ((idstr = id_attr.getValue()) == null))
639         {
640             throw new rssParseException("Channel parse error: rss-channel ID isn't specified");
641         }
642 
643         // SETTING ID
644         int id;
645         try
646         {
647             id = Integer.parseInt(idstr);
648             this.setID(id);
649         }
650         catch (NumberFormatException nfe)
651         {
652             throw new rssParseException("Channel parse error: invalid ID format or can't convert string into int value");
653         }
654 
655 
656         for (int i=0; i < child_num; i++)
657         {
658             curr_node = nl.item(i);
659 
660             if (curr_node.getNodeType() == Node.ELEMENT_NODE)
661             {
662                 node_name = curr_node.getNodeName();
663                 if (node_name.equalsIgnoreCase("dc:title"))
664                 {
665                     if ((temp = curr_node.getFirstChild()) != null)
666                        this.setTitle(temp.getNodeValue());
667                     else
668                        this.setTitle("");
669                 }
670                 else if (node_name.equalsIgnoreCase("dc:description"))
671                 {
672                     if ((temp = curr_node.getFirstChild()) != null)
673                        this.setDescription(temp.getNodeValue());
674                     else
675                        this.setDescription("");
676                 }
677                 else if (node_name.equalsIgnoreCase("dateCreated"))
678                 {
679                     if ((temp = curr_node.getFirstChild()) != null)
680                        setDateCreated(rssDateHandler.getDateInstanceFromRSS(temp.getNodeValue()));
681                 }
682                 else if (node_name.equalsIgnoreCase("dc:creator"))
683                 {
684                     if ((temp = curr_node.getFirstChild()) != null)
685                        this.setCreator(temp.getNodeValue());
686                     else
687                        this.setCreator("");
688                 }
689                 else if (node_name.equalsIgnoreCase("dc:source"))
690                 {
691                     if ((temp = curr_node.getFirstChild()) != null)
692                        this.setSource(temp.getNodeValue());
693                     else
694                     {
695                         throw new rssParseException("JNR format parse error: dc:source element is empty");
696                     }
697 
698                 }
699                 else if (node_name.equalsIgnoreCase("link"))
700                 {
701                     if ((temp = curr_node.getFirstChild()) != null)
702                        this.setLink(temp.getNodeValue());
703                     else
704                        throw new rssParseException("RSS channel: link element contains no data");
705                 }
706                 else if (node_name.equalsIgnoreCase("keepPeriod"))
707                 {
708                     if ((temp = curr_node.getFirstChild()) != null)
709                        this.setKeepPeriod(Integer.parseInt(temp.getNodeValue()));
710                 }
711                 else if (node_name.equalsIgnoreCase("image")) //we've got image
712                 {
713                     Node t_node;
714                     NodeList t_ls = curr_node.getChildNodes();
715                     String t_name;
716 
717                     for (int t_i = 0; t_i < t_ls.getLength(); t_i++)
718                     {
719                         t_node = t_ls.item(t_i);
720 
721                         if (t_node.getNodeType() == Node.ELEMENT_NODE)
722                         {
723                             //no parse exceptions, only known values will be set
724                             //image url is set using about attribute
725                             t_name = curr_node.getNodeName();
726                             if (t_name.equalsIgnoreCase("title"))
727                             {
728                                 if ((temp = t_node.getFirstChild()) != null)
729                                     this.setImageTitle(temp.getNodeValue());
730                             }
731                             if (t_name.equalsIgnoreCase("link"))
732                             {
733                                 if ((temp = t_node.getFirstChild()) != null)
734                                     this.setImageLink(temp.getNodeValue());
735                             }
736                             if (t_name.equalsIgnoreCase("url"))
737                             {
738                                 if ((temp = t_node.getFirstChild()) != null)
739                                     this.setImageURL(temp.getNodeValue());
740                             }
741                         }
742                     }
743                 }
744                 else if (node_name.equalsIgnoreCase("ttl"))
745                 {
746                     if ((temp = curr_node.getFirstChild()) != null)
747                        this.setTtl(Integer.parseInt(temp.getNodeValue()));
748                 }
749                 else if (node_name.equalsIgnoreCase("dc:language"))
750                 {
751                     if ((temp = curr_node.getFirstChild()) != null)
752                         this.setLanguage(temp.getNodeValue());
753                     else
754                         this.setLanguage("en-us");  // default value
755                 }
756                 else if (node_name.equalsIgnoreCase("item"))
757                 {
758                     new_i = new rssItem();
759                     try
760                     {
761                         new_i.parse((Element)curr_node);
762                         new_i.setID(new_i.generateID());
763                     }
764                     catch (rssParseException pe)
765                     {
766                         throw new rssParseException("rssChannel parse error: "+ pe.toString());
767                     }
768 
769                     this.addItem(new_i);
770                 }
771             }//end of ELEMENT_NODE
772         }//end of for
773 
774     }
775 
776     /**
777      * Adds new RSS item to the channel's item list
778      *
779      * @param ni new item
780      *
781      * @return boolean true if item was added, false
782      *         otherwise (item already exists or add failure)
783      */
784     public boolean addItem(rssItem ni)
785     {
786         synchronized (itemList)
787         {
788             if (itemList.containsKey(new Integer(ni.getID())))
789             {
790                 return false;
791             }
792             else
793             {
794                 // MAX - means we're keep all, 0 - will be rejected on saving
795                 if (keepPeriod == MAX_KEEP_PERIOD || keepPeriod == 0) {
796                     itemList.put(new Integer(ni.getID()),ni);
797                 }
798                 else {
799                     Calendar c = Calendar.getInstance();
800                     int day = c.get(Calendar.DAY_OF_YEAR) - keepPeriod;
801                     c.set(Calendar.DAY_OF_YEAR, day);
802 
803                     if (ni.getDateCreated().compareTo(c.getTime()) >= 0) {
804                         itemList.put(new Integer(ni.getID()),ni);
805                     }
806                 }
807 
808             }
809         }
810         return true;
811     }
812 
813     /**
814      * Overrides default from AbstractEntry
815      * @param title
816      */
817     public void setTitle(String title)
818     {
819         if (isUpdateOperation == false)
820             this.title = new String(title);
821     }
822 
823     /**
824      * Overrides default from AbstractEntry
825      * @param description
826      */
827     public void setDescription(String description)
828     {
829         if (isUpdateOperation == false)
830             this.description = new String(description);
831     }
832 
833     public String getSource()
834     {
835         return source;
836     }
837 
838     public void setSource(String source)
839     {
840         if (isUpdateOperation == false)
841             this.source = new String(source);
842     }
843 
844     public String getLanguage()
845     {
846         return language;
847     }
848 
849     public void setLanguage(String language)
850     {
851         this.language = new String(language);
852     }
853 
854     public String getCreator()
855     {
856         return creator;
857     }
858 
859     public void setCreator(String creator)
860     {
861        this.creator = new String(creator);
862     }
863 
864     public String getLink()
865     {
866        return link;
867     }
868 
869     public void setLink(String link)
870     {
871        this.link = new String(link);
872     }
873 
874     public int getTtl()
875     {
876         return ttl;
877     }
878 
879     public void setTtl(int ttl)
880     {
881         if (isUpdateOperation == false)
882             this.ttl = ttl;
883     }
884 
885     public String getImageTitle()
886     {
887         return imageTitle;
888     }
889 
890     public void setImageTitle(String imageTitle)
891     {
892         this.imageTitle = new String(imageTitle);
893     }
894 
895     public String getImageURL()
896     {
897         return imageURL;
898     }
899 
900     public void setImageURL(String imageURL)
901     {
902         this.imageURL = new String(imageURL);
903     }
904 
905     public String getImageLink()
906     {
907         return imageLink;
908     }
909 
910     public void setImageLink(String imageLink)
911     {
912         this.imageLink = new String(imageLink);
913     }
914 
915     /**
916      * Returns true if channel has unread(fresh) items
917      *
918      */
919     public boolean isFresh()
920     {
921         synchronized (itemList) {
922             for (Iterator i = itemList.keySet().iterator(); i.hasNext();)
923                 if  (((rssItem) itemList.get(i.next())).isFresh)
924                     return true;
925         }
926         return false;
927     }
928 
929 
930     /**
931      * Set keep period in days
932      */
933     public void setKeepPeriod(int p) {
934         keepPeriod = p;
935     }
936 
937     /**
938      * Get keep period in days
939      */
940     public int getKeepPeriod() {
941         return keepPeriod;
942     }
943 
944     /**
945      * Filter items
946      *
947      * <p>Remove unwanted items using keepPeriod rule</p>
948      */
949     public void filterItems() {
950         if ((keepPeriod > 0) && (keepPeriod < MAX_KEEP_PERIOD))
951         {
952             Calendar c = Calendar.getInstance();
953             int day = c.get(Calendar.DAY_OF_YEAR) - keepPeriod;
954             c.set(Calendar.DAY_OF_YEAR, day);
955             Date d = c.getTime();
956 
957             synchronized (itemList) {
958                 for (Iterator i = itemList.keySet().iterator(); i.hasNext();)
959                 {
960                     if (((rssItem) itemList.get(i.next())).getDateCreated().compareTo(d) < 0)
961                         i.remove();
962                 }
963             }
964         }
965     }
966 
967     /**
968      * Filter items using specified filter
969      *
970      * @param f
971      */
972     public void filterItems(RssItemFilter f) {
973 
974         if (f == null)
975             return;
976 
977         Vector v = f.filter(getItemVector());
978         itemList = new HashMap();
979         rssItem item = null;
980 
981         for (int i=0, n = v.size(); i < n;  i++) {
982             item = (rssItem)v.get(i);
983             itemList.put(new Integer(item.getID()), item);
984         }
985 
986 
987     }
988 
989 
990 
991 }