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

Quick Search    Search Deep

Source code: com/fm/rss/rssChannelCategory.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  
16  import org.w3c.dom.*;
17  import javax.xml.parsers.DocumentBuilder;
18  import javax.xml.parsers.DocumentBuilderFactory;
19  import javax.xml.parsers.ParserConfigurationException;
20  
21  import com.fm.update.updateException;
22  import com.fm.update.Updateable;
23  import com.fm.rss.filter.RssItemFilter;
24  
25  /**
26   * Container for RSS channel entities. Channel categories are intended for the
27   * user defined grouping of RSS channels (e.g. Developer's news,XML news)
28   *
29   * @author Andrew Duka (Andrew.Duka@oktet.ru)
30   */
31  public class rssChannelCategory extends rssAbstractEntry implements ItemContainer, Updateable
32  {
33  
34      private HashMap subCategories;  /* has table for sub categories */
35      private HashMap channels;       /* hash table for channels */
36  
37      private String version;
38  
39  
40      /**
41       * Default constructor
42       */
43      public rssChannelCategory ()
44      {
45          subCategories = new HashMap();
46          channels = new HashMap();
47  
48          setID(0);
49          setTitle("");
50          setDescription("");
51          setDateCreated(new Date());
52          version = "1.0";
53      }
54  
55      /**
56       * Constructs category using given title and description and ID
57       *
58       * @param t  String with category title
59       * @param d  String with category description
60       */
61      public rssChannelCategory(String t, String d)
62      {
63          subCategories = new HashMap();
64          channels = new HashMap();
65  
66          setTitle(t);
67          setDescription(d);
68          setDateCreated(new Date());
69      }
70  
71      /**
72       * Adds new category to the sub categories list
73       *
74       * @param cat rssChannelCategory object representing category to add
75       * @return true on success, false if failed or category already exists
76       */
77      public boolean addSubCategory(rssChannelCategory cat)
78      {
79          synchronized (subCategories)
80          {
81              if (subCategories.containsKey(new Integer(cat.getID())) == true)
82                  return false;
83              else
84                  subCategories.put(new Integer(cat.getID()), cat);
85              return true;
86          }
87      }
88  
89      /**
90       * Removes sub category specified by ID from sub categories
91       *
92       * @param category category to remove
93       * @return true on success, false if failed or category doesn't exist
94       */
95      public synchronized boolean removeSubCategory(rssChannelCategory category)
96      {
97          synchronized (subCategories)
98          {
99              if (subCategories.containsKey(new Integer(category.getID())) == false)
100                 return false;
101             else
102                 subCategories.remove(new Integer(category.getID()));
103             return true;
104         }
105     }
106 
107     /**
108      * Replaces sub category specified by ID with given one
109      *
110      * @param  catID ID of category to replace
111      * @param  cat   new category
112      * @return true on success, false if failed or category doesn't exist
113      */
114     public boolean replaceSubCategory(int catID, rssChannelCategory cat)
115     {
116         synchronized (subCategories)
117         {
118             if (subCategories.containsKey(new Integer(catID)) == false)
119                 return false;
120             else
121                 subCategories.put(new Integer(catID), cat);
122             return true;
123         }
124     }
125 
126     /**
127      * Adds new channel to the channel list
128      *
129      * @param ch rssChannel object representing category to add
130      * @return true on success, false if failed or category already exists
131      */
132     public boolean addChannel(rssChannel ch)
133     {
134         synchronized (channels)
135         {
136             if (channels.containsKey(new Integer(ch.getID())) == true)
137             {
138                 return false; // already have channel with same ID
139             }
140             else
141                 channels.put(new Integer(ch.getID()), ch);
142             return true;
143         }
144     }
145 
146     /**
147      * Removes channel specified by ID from channels
148      *
149      * @param channel channel to remove
150      * @return true on success, false if failed or category doesn't exist
151      */
152     public synchronized boolean removeChannel(rssChannel channel)
153     {
154         synchronized (channels)
155         {
156             if (channels.containsKey(new Integer(channel.getID())) == false)
157                 return false;
158             else
159                 channels.remove(new Integer(channel.getID()));
160             return true;
161         }
162     }
163 
164     /**
165      * Replaces channel specified by ID with given one
166      *
167      * @param  channelID ID of channel to replace
168      * @param  ch   new channel
169      * @return true on success, false if failed or category doesn't exist
170      */
171     public boolean replaceChannel(int channelID, rssChannel ch)
172     {
173         synchronized (channels)
174         {
175             if (channels.containsKey(new Integer(channelID)) == false)
176                 return false;
177             else
178                 channels.put(new Integer(channelID), ch);
179             return true;
180         }
181     }
182 
183     /**
184      * Returns sub categories as a list
185      *
186      * @return ArrayList containing sub categories
187      */
188     public Map getSubCategories()
189     {
190         return subCategories;
191     }
192 
193     /**
194      * Returns channels as a list
195      *
196      * @return ArrayList containing category channels
197      */
198     public Map getChannels()
199     {
200         return this.channels;
201     }
202 
203     /**
204      * Parse Element object and initialize category properties and channel list.
205      *
206      * <p>The <code>parse()</code> method for the channel categories works only
207      * with proprietary JNR format</p>
208      *
209      * @param el
210      * @throws com.fm.rss.rssParseException
211      */
212     public synchronized void parse(Element el) throws rssParseException
213     {
214         // checking for version
215         //System.out.println(el.toString());
216         String ver = (el.getAttributeNode("version")).getValue();
217         if ((ver == null) || this.version.compareTo(ver) != 0)
218         {
219             throw new rssParseException("Category parse error: Incompatible rss-channel-category version");
220         }
221 
222         Attr id_attr = el.getAttributeNode("id");
223         String idstr;
224         if ((id_attr == null) || ((idstr = id_attr.getValue()) == null))
225         {
226             throw new rssParseException("Category parse error: category ID isn't specified");
227         }
228         // setting ID
229         int id;
230         try
231         {
232             id = Integer.parseInt(idstr);
233             this.setID(id);
234         }
235         catch (NumberFormatException nfe)
236         {
237             throw new rssParseException("Can't set ID: invalid format or can't convert string into int value");
238         }
239 
240 
241 
242         Node curr_node;
243         Node temp;
244         NodeList nl = el.getChildNodes();
245         rssChannel new_ch;
246         rssChannelCategory new_cat;
247         int child_num = nl.getLength();
248         String node_name;
249 
250         for (int i=0; i < child_num; i++)
251         {
252             curr_node = nl.item(i);
253 
254             if (curr_node.getNodeType() == Node.ELEMENT_NODE)
255             {
256                 node_name = curr_node.getNodeName();
257                 if (node_name.equalsIgnoreCase("dc:title"))
258                 {
259                     if ((temp = curr_node.getFirstChild()) != null)
260                        this.setTitle(temp.getNodeValue());
261                     else
262                     {
263                         throw new rssParseException("JNR format parse error: dc:title element is empty");
264                     }
265                 }
266                 else if (node_name.equalsIgnoreCase("dc:description"))
267                 {
268                     if ((temp = curr_node.getFirstChild()) != null)
269                        this.setDescription(temp.getNodeValue());
270                     else
271                     {
272                        this.setDescription("");
273                     }
274                 }
275                 else if (node_name.equalsIgnoreCase("dateCreated"))
276                 {
277                     if ((temp = curr_node.getFirstChild()) != null)
278                        setDateCreated(rssDateHandler.getDateInstanceFromRSS(temp.getNodeValue()));
279                     else
280                     {
281                         throw new rssParseException("JNR format parse error: dc:dateCreated element is empty");
282                     }
283                 }
284                 else if (node_name.equalsIgnoreCase("dcterms:hasPart"))
285                 {
286                     // getting only first child
287                     Node f_ch = curr_node.getFirstChild();
288                     String ch_t = f_ch.getNodeName();
289 
290                     // category case
291                     if (ch_t.equalsIgnoreCase("rss-channel-category"))
292                     {
293                         new_cat = new rssChannelCategory();
294                         try
295                         {
296                             new_cat.parse((Element)f_ch);
297                         }
298                         catch (rssParseException pe)
299                         {
300                             throw new rssParseException("Sub category parse exception: " + pe.toString());
301                         }
302                         this.addSubCategory(new_cat);
303                     } // channel case
304                     else if (ch_t.equalsIgnoreCase("rss-channel"))
305                     {
306                         new_ch = new rssChannel();
307                         try
308                         {
309                             new_ch.parse((Element)f_ch);
310                         }
311                         catch (rssParseException pe)
312                         {
313                             throw new rssParseException("Channel parse exception: " + pe.toString());
314                         }
315                         this.addChannel(new_ch);
316                     }
317                 }//end of hasPart
318             }//end of ELEMENT_NODE
319         }//end of for
320     }
321 
322 
323     /**
324      * Return item container as element of XML document
325      *
326      * @return DOM Element object with representation of the item container
327      */
328     public Element toDomElement()
329     {
330         Element root_elem;
331         if (this.docAdapter == null)
332         {
333             try
334             {
335                 docAdapter = documentAdapter.newInstance();
336             }
337             catch (ParserConfigurationException pce)
338             {
339                 //catch exception here
340                 return null;
341             }
342         }
343 
344         root_elem = this.docAdapter.createElement("rss-channel-category");
345 
346         try
347         {
348             // ID & Version
349             root_elem.setAttribute("id", Integer.toString(this.getID()));
350             root_elem.setAttribute("version", "1.0");
351 
352             //  Title, Description, dateCreated
353             Element c_t = this.docAdapter.createElement("title",
354                                                         "dc",
355                                                         documentAdapter.DC_NAMESPACE_URI);
356 
357             c_t.appendChild(this.docAdapter.createTextNode(this.getTitle()));
358 
359             Element c_d = this.docAdapter.createElement("description",
360                                                         "dc",
361                                                         documentAdapter.DC_NAMESPACE_URI);
362             c_d.appendChild(this.docAdapter.createTextNode(this.getDescription()));
363 
364             Element c_dc = this.docAdapter.createElement("dateCreated",
365                                                          "dcterms",
366                                                          documentAdapter.DCTERMS_NAMESPACE_URI);
367             c_dc.appendChild(this.docAdapter.
368                                   createTextNode(rssDateHandler.
369                                                     dateToString(getDateCreated(),
370                                                                  rssDateHandler.RSS_OUTPUT_PATTERN)));
371 
372             root_elem.appendChild(c_t);
373             root_elem.appendChild(c_d);
374             root_elem.appendChild(c_dc);
375 
376             // channels & categories
377             Element sub_entry;
378             Element has_part;
379 
380             // dumping sub categories
381             synchronized (subCategories)
382             {
383                 for (Iterator it = subCategories.keySet().iterator(); it.hasNext();)
384                 {
385                     sub_entry = (((rssAbstractEntry)(subCategories.get(it.next()))).toDomElement());
386                     if (sub_entry != null)
387                     {
388                         has_part = this.docAdapter.createElement("hasPart",
389                                                                  "dcterms",
390                                                                  documentAdapter.DCTERMS_NAMESPACE_URI);
391                         has_part.appendChild(sub_entry);
392                         root_elem.appendChild(has_part);
393                     }
394                     else
395                     {
396                         //possibly report error here
397                     }
398                 }
399             }
400             // same for channels
401             synchronized (channels)
402             {
403                 for (Iterator it = channels.keySet().iterator(); it.hasNext();)
404                 {
405                     sub_entry = (((rssAbstractEntry)(channels.get(it.next()))).toDomElement());
406                     if (sub_entry != null)
407                     {
408                         has_part = this.docAdapter.createElement("hasPart",
409                                                                  "dcterms",
410                                                                   documentAdapter.DC_NAMESPACE_URI);
411                         has_part.appendChild(sub_entry);
412                         root_elem.appendChild(has_part);
413                     }
414                     else
415                     {
416                         //possibly report error here
417                     }
418                 }
419             }
420         }
421         catch (DOMException e)
422         {
423             return null;
424         }
425 
426         return root_elem;
427     }
428 
429     /**
430      * Update category channels. This method will subsequently update
431      * all channels and sub categories associated with the category.
432      *
433      * @throws com.fm.update.updateException if error occured during update
434      */
435     public void update() throws updateException
436     {
437         // updating sub categories
438         synchronized (subCategories)
439         {
440             for (Iterator it = subCategories.values().iterator(); it.hasNext();)
441             {
442                 try
443                 {
444                     ((rssChannelCategory)it.next()).update();
445                 }
446                 catch (updateException upe)
447                 {
448                     throw upe;
449                 }
450             }
451         }
452         // same for channels
453         synchronized (channels)
454         {
455             for (Iterator it = channels.values().iterator(); it.hasNext();)
456             {
457                 try
458                 {
459                     ((rssChannel)it.next()).update();
460                 }
461                 catch (updateException upe)
462                 {
463                     throw upe;
464                 }
465 
466             }
467         }
468     }
469 
470     /**
471      * Returns list of the container items
472      *
473      * @return list of the channel items
474      */
475     public Map getItems()
476     {
477         HashMap result = new HashMap();
478         Map temp_mp;
479 
480         // updating sub categories
481         synchronized (subCategories)
482         {
483 
484             for (Iterator it = subCategories.keySet().iterator(); it.hasNext();)
485             {
486                 // do update in the sub category, if new items are retreived -
487                 // put them into result list
488                 if ((temp_mp = ((ItemContainer)subCategories.get(it.next())).getItems()) !=
489                      null)
490                 {
491                      result.putAll(temp_mp);
492                 }
493 
494             }
495         }
496         // same for channels
497         synchronized (channels)
498         {
499             for (Iterator it = channels.keySet().iterator(); it.hasNext();)
500             {
501                 if ((temp_mp = ((ItemContainer)channels.get(it.next())).getItems()) !=
502                       null)
503                 {
504                     result.putAll(temp_mp);
505                 }
506             }
507         }
508         return (result.size() > 0) ? result : null;
509     }
510 
511     /**
512      * Filter items using specified filter
513      *
514      * @param f
515      */
516     public void filterItems(RssItemFilter f)
517     {
518         if (f == null)
519             return;
520 
521         synchronized (subCategories) {
522             for (Iterator i = subCategories.values().iterator(); i.hasNext();)
523                 ((ItemContainer) i.next()).filterItems(f);
524         }
525 
526         synchronized (channels) {
527             for (Iterator i = channels.values().iterator(); i.hasNext();)
528                 ((ItemContainer) i.next()).filterItems(f);
529         }
530 
531     }
532 
533 
534 }