View Javadoc

1   /*
2    * Copyright 2004 Sun Microsystems, Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   */
17  package com.sun.syndication.feed.synd;
18  
19  import com.sun.syndication.feed.impl.ObjectBean;
20  import com.sun.syndication.feed.impl.CopyFromHelper;
21  import com.sun.syndication.feed.WireFeed;
22  import com.sun.syndication.feed.module.*;
23  import com.sun.syndication.feed.module.impl.ModuleUtils;
24  import com.sun.syndication.feed.synd.impl.Converters;
25  import com.sun.syndication.feed.synd.impl.URINormalizer;
26  
27  import java.util.*;
28  import java.io.Serializable;
29  
30  /***
31   * Bean for all types of feeds.
32   * <p>
33   * It handles all RSS versions and Atom 0.3, it normalizes all info, it may lose information.
34   * <p>
35   * @author Alejandro Abdelnur
36   *
37   */
38  public class SyndFeedImpl implements Serializable,SyndFeed {
39      private ObjectBean _objBean;
40      private String _encoding;
41      private String _uri;
42      private String _title;
43      private String _feedType;
44      private String _link;
45      private String _description;
46      private SyndImage _image;
47      private List _entries;
48      private List _modules;
49  
50      private static final Converters CONVERTERS = new Converters();
51  
52      private static final Set IGNORE_PROPERTIES = new HashSet();
53  
54      /***
55       * Unmodifiable Set containing the convenience properties of this class.
56       * <p>
57       * Convenience properties are mapped to Modules, for cloning the convenience properties
58       * can be ignored as the will be copied as part of the module cloning.
59       */
60  
61      public static final Set CONVENIENCE_PROPERTIES = Collections.unmodifiableSet(IGNORE_PROPERTIES);
62  
63      static {
64          IGNORE_PROPERTIES.add("publishedDate");
65          IGNORE_PROPERTIES.add("author");
66          IGNORE_PROPERTIES.add("copyright");
67          IGNORE_PROPERTIES.add("categories");
68          IGNORE_PROPERTIES.add("language");
69      }
70  
71      /***
72       * Returns the real feed types the SyndFeedImpl supports when converting from and to.
73       * <p>
74       * @return the real feed type supported.
75       */
76      public List getSupportedFeedTypes() {
77          return CONVERTERS.getSupportedFeedTypes();
78      }
79  
80      /***
81       * For implementations extending SyndFeedImpl to be able to use the ObjectBean functionality
82       * with extended interfaces.
83       * <p>
84       * @param beanClass
85       * @param convenienceProperties set containing the convenience properties of the SyndEntryImpl
86       * (the are ignored during cloning, check CloneableBean for details).
87       *
88       */
89      protected SyndFeedImpl(Class beanClass,Set convenienceProperties) {
90          _objBean = new ObjectBean(beanClass,this,convenienceProperties);
91      }
92  
93      /***
94       * Default constructor. All properties are set to <b>null</b>.
95       * <p>
96       *
97       */
98      public SyndFeedImpl() {
99          this(null);
100     }
101 
102     /***
103      * Creates a SyndFeedImpl and populates all its properties out of the
104      * given RSS Channel or Atom Feed properties.
105      * <p>
106      * @param feed the RSS Channel or the Atom Feed to populate the properties from.
107      *
108      */
109     public SyndFeedImpl(WireFeed feed) {
110         this(SyndFeed.class,IGNORE_PROPERTIES);
111         if (feed!=null) {
112             _feedType = feed.getFeedType();
113             Converter converter = CONVERTERS.getConverter(_feedType);
114             if (converter==null) {
115                 throw new IllegalArgumentException("Invalid feed type ["+_feedType+"]");
116             }
117             converter.copyInto(feed,this);
118         }
119     }
120 
121     /***
122      * Creates a deep 'bean' clone of the object.
123      * <p>
124      * @return a clone of the object.
125      * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned.
126      *
127      */
128     public Object clone() throws CloneNotSupportedException {
129         return _objBean.clone();
130     }
131 
132     /***
133      * Indicates whether some other object is "equal to" this one as defined by the Object equals() method.
134      * <p>
135      * @param other he reference object with which to compare.
136      * @return <b>true</b> if 'this' object is equal to the 'other' object.
137      *
138      */
139     public boolean equals(Object other) {
140         return _objBean.equals(other);
141     }
142 
143     /***
144      * Returns a hashcode value for the object.
145      * <p>
146      * It follows the contract defined by the Object hashCode() method.
147      * <p>
148      * @return the hashcode of the bean object.
149      *
150      */
151     public int hashCode() {
152         return _objBean.hashCode();
153     }
154 
155     /***
156      * Returns the String representation for the object.
157      * <p>
158      * @return String representation for the object.
159      *
160      */
161     public String toString() {
162         return _objBean.toString();
163     }
164 
165     /***
166      * Creates a real feed containing the information of the SyndFeedImpl.
167      * <p>
168      * The feed type of the created WireFeed is taken from the SyndFeedImpl feedType property.
169      * <p>
170      * @return the real feed.
171      *
172      */
173     public WireFeed createWireFeed() {
174         return createWireFeed(_feedType);
175     }
176 
177     /***
178      * Creates a real feed containing the information of the SyndFeedImpl.
179      * <p>
180      * @param feedType the feed type for the WireFeed to be created.
181      * @return the real feed.
182      *
183      */
184     public WireFeed createWireFeed(String feedType) {
185         if (feedType==null) {
186             throw new IllegalArgumentException("Feed type cannot be null");
187         }
188         Converter converter = CONVERTERS.getConverter(feedType);
189         if (converter==null) {
190             throw new IllegalArgumentException("Invalid feed type ["+feedType+"]");
191         }
192         return converter.createRealFeed(this);
193     }
194 
195     /***
196      * Returns the wire feed type the feed had/will-have when coverted from/to a WireFeed.
197      * <p>
198      * @return the feed type, <b>null</b> if none.
199      *
200      */
201     public String getFeedType() {
202         return _feedType;
203     }
204 
205     /***
206      * Sets the wire feed type the feed will-have when coverted to a WireFeed.
207      * <p>
208      * @param feedType the feed type to set, <b>null</b> if none.
209      *
210      */
211     public void setFeedType(String feedType) {
212         _feedType = feedType;
213     }
214 
215     /***
216      * Returns the charset encoding of a the feed. This is not set by Rome parsers.
217      * <p>
218      * @return the charset encoding of the feed.
219      *
220      */
221     public String getEncoding() {
222         return _encoding;
223     }
224 
225     /***
226      * Sets the charset encoding of a the feed. This is not set by Rome parsers.
227      * <p>
228      * @param encoding the charset encoding of the feed.
229      *
230      */
231     public void setEncoding(String encoding) {
232         _encoding = encoding;
233     }
234 
235     /***
236      * Returns the feed URI.
237      * <p>
238      * How the feed URI maps to a concrete feed type (RSS or Atom) depends on
239      * the concrete feed type. This is explained in detail in Rome documentation,
240      * <a href="http://wiki.java.net/bin/edit/Javawsxml/Rome04URIMapping">Feed and entry URI mapping</a>.
241      * <p>
242      * The returned URI is a normalized URI as specified in RFC 2396bis.
243      * <p>
244      * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is
245      * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link
246      * is the URL that the item is accessible under, the URI is the
247      * permanent identifier which the aggregator should use to reference
248      * this item. Often the URI will use some standardized identifier scheme
249      * such as DOI's so that items can be identified even if they appear in
250      * multiple feeds with different "links" (they might be on different
251      * hosting platforms but be the same item). Also, though rare, there
252      * could be multiple items with the same link but a different URI and
253      * associated metadata which need to be treated as distinct entities.
254      * In the RSS 1.0 case the URI must be a valid RDF URI reference.
255      * <p>
256      * @return the feed URI, <b>null</b> if none.
257      *
258      */
259     public String getUri() {
260         return _uri;
261     }
262 
263     /***
264      * Sets the feed URI.
265      * <p>
266      * How the feed URI maps to a concrete feed type (RSS or Atom) depends on
267      * the concrete feed type. This is explained in detail in Rome documentation,
268      * <a href="http://wiki.java.net/bin/edit/Javawsxml/Rome04URIMapping">Feed and entry URI mapping</a>.
269      * <p>
270      * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is
271      * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link
272      * is the URL that the item is accessible under, the URI is the
273      * permanent identifier which the aggregator should use to reference
274      * this item. Often the URI will use some standardized identifier scheme
275      * such as DOI's so that items can be identified even if they appear in
276      * multiple feeds with different "links" (they might be on different
277      * hosting platforms but be the same item). Also, though rare, there
278      * could be multiple items with the same link but a different URI and
279      * associated metadata which need to be treated as distinct entities.
280      * In the RSS 1.0 case the URI must be a valid RDF URI reference.
281      * <p>
282      * @param uri the feed URI to set, <b>null</b> if none.
283      *
284      */
285     public void setUri(String uri) {
286         _uri = URINormalizer.normalize(uri);
287     }
288 
289     /***
290      * Returns the feed title.
291      * <p>
292      * @return the feed title, <b>null</b> if none.
293      *
294      */
295     public String getTitle() {
296         return _title;
297     }
298 
299     /***
300      * Sets the feed title.
301      * <p>
302      * @param title the feed title to set, <b>null</b> if none.
303      *
304      */
305     public void setTitle(String title) {
306         _title = title;
307     }
308 
309     /***
310      * Returns the feed link.
311      * <p>
312      * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is
313      * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link
314      * is the URL that the item is accessible under, the URI is the
315      * permanent identifier which the aggregator should use to reference
316      * this item. Often the URI will use some standardized identifier scheme
317      * such as DOI's so that items can be identified even if they appear in
318      * multiple feeds with different "links" (they might be on different
319      * hosting platforms but be the same item). Also, though rare, there
320      * could be multiple items with the same link but a different URI and
321      * associated metadata which need to be treated as distinct entities.
322      * In the RSS 1.0 case the URI must be a valid RDF URI reference.
323      * <p>
324      * @return the feed link, <b>null</b> if none.
325      *
326      */
327     public String getLink() {
328         return _link;
329     }
330 
331     /***
332      * Sets the feed link.
333      * <p>
334      * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is
335      * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link
336      * is the URL that the item is accessible under, the URI is the
337      * permanent identifier which the aggregator should use to reference
338      * this item. Often the URI will use some standardized identifier scheme
339      * such as DOI's so that items can be identified even if they appear in
340      * multiple feeds with different "links" (they might be on different
341      * hosting platforms but be the same item). Also, though rare, there
342      * could be multiple items with the same link but a different URI and
343      * associated metadata which need to be treated as distinct entities.
344      * In the RSS 1.0 case the URI must be a valid RDF URI reference.
345      * <p>
346      * @param link the feed link to set, <b>null</b> if none.
347      *
348      */
349     public void setLink(String link) {
350         _link = link;
351     }
352 
353     /***
354      * Returns the feed description.
355      * <p>
356      * @return the feed description, <b>null</b> if none.
357      *
358      */
359     public String getDescription() {
360         return _description;
361     }
362 
363     /***
364      * Sets the feed description.
365      * <p>
366      * @param description the feed description to set, <b>null</b> if none.
367      *
368      */
369     public void setDescription(String description) {
370         _description = description;
371     }
372 
373     /***
374      * Returns the feed published date.
375      * <p>
376      * This method is a convenience method, it maps to the Dublin Core module date.
377      * <p>
378      * @return the feed published date, <b>null</b> if none.
379      *
380      */
381     public Date getPublishedDate() {
382         return getDCModule().getDate();
383     }
384 
385     /***
386      * Sets the feed published date.
387      * <p>
388      * This method is a convenience method, it maps to the Dublin Core module date.
389      * <p>
390      * @param publishedDate the feed published date to set, <b>null</b> if none.
391      *
392      */
393     public void setPublishedDate(Date publishedDate) {
394         getDCModule().setDate(publishedDate);
395     }
396 
397     /***
398      * Returns the feed author.
399      * <p>
400      * This method is a convenience method, it maps to the Dublin Core module creator.
401      * <p>
402      * @return the feed author, <b>null</b> if none.
403      *
404      */
405     public String getAuthor() {
406         return getDCModule().getCreator();
407     }
408 
409     /***
410      * Sets the feed author.
411      * <p>
412      * This method is a convenience method, it maps to the Dublin Core module creator.
413      * <p>
414      * @param author the feed author to set, <b>null</b> if none.
415      *
416      */
417     public void setAuthor(String author) {
418         getDCModule().setCreator(author);
419     }
420 
421     /***
422      * Returns the feed copyright.
423      * <p>
424      * This method is a convenience method, it maps to the Dublin Core module rights.
425      * <p>
426      * @return the feed copyright, <b>null</b> if none.
427      *
428      */
429     public String getCopyright() {
430         return getDCModule().getRights();
431     }
432 
433     /***
434      * Sets the feed copyright.
435      * <p>
436      * This method is a convenience method, it maps to the Dublin Core module rights.
437      * <p>
438      * @param copyright the feed copyright to set, <b>null</b> if none.
439      *
440      */
441     public void setCopyright(String copyright) {
442         getDCModule().setRights(copyright);
443     }
444 
445     /***
446      * Returns the feed image.
447      * <p>
448      * @return the feed image, <b>null</b> if none.
449      *
450      */
451     public SyndImage getImage() {
452         return _image;
453     }
454 
455     /***
456      * Sets the feed image.
457      * <p>
458      * @param image the feed image to set, <b>null</b> if none.
459      *
460      */
461     public void setImage(SyndImage image) {
462         _image = image;
463     }
464 
465     /***
466      * Returns the feed categories.
467      * <p>
468      * This method is a convenience method, it maps to the Dublin Core module subjects.
469      * <p>
470      * @return a list of SyndCategoryImpl elements with the feed categories,
471      *         an empty list if none.
472      *
473      */
474     public List getCategories() {
475         return new SyndCategoryListFacade(getDCModule().getSubjects());
476     }
477 
478     /***
479      * Sets the feed categories.
480      * <p>
481      * This method is a convenience method, it maps to the Dublin Core module subjects.
482      * <p>
483      * @param categories the list of SyndCategoryImpl elements with the feed categories to set,
484      *        an empty list or <b>null</b> if none.
485      *
486      */
487     public void setCategories(List categories) {
488         getDCModule().setSubjects(SyndCategoryListFacade.convertElementsSyndCategoryToSubject(categories));
489     }
490 
491     /***
492      * Returns the feed entries.
493      * <p>
494      * @return a list of SyndEntryImpl elements with the feed entries,
495      *         an empty list if none.
496      *
497      */
498     public List getEntries() {
499         return (_entries==null) ? (_entries=new ArrayList()) : _entries;
500     }
501 
502     /***
503      * Sets the feed entries.
504      * <p>
505      * @param entries the list of SyndEntryImpl elements with the feed entries to set,
506      *        an empty list or <b>null</b> if none.
507      *
508      */
509     public void setEntries(List entries) {
510         _entries = entries;
511     }
512 
513     /***
514      * Returns the feed language.
515      * <p>
516      * This method is a convenience method, it maps to the Dublin Core module language.
517      * <p>
518      * @return the feed language, <b>null</b> if none.
519      *
520      */
521     public String getLanguage() {
522         return getDCModule().getLanguage();
523     }
524 
525     /***
526      * Sets the feed language.
527      * <p>
528      * This method is a convenience method, it maps to the Dublin Core module language.
529      * <p>
530      * @param language the feed language to set, <b>null</b> if none.
531      *
532      */
533     public void setLanguage(String language) {
534         getDCModule().setLanguage(language);
535     }
536 
537     /***
538      * Returns the feed modules.
539      * <p>
540      * @return a list of ModuleImpl elements with the feed modules,
541      *         an empty list if none.
542      *
543      */
544     public List getModules() {
545         if  (_modules==null) {
546             _modules=new ArrayList();
547         }
548         if (ModuleUtils.getModule(_modules,DCModule.URI)==null) {
549             _modules.add(new DCModuleImpl());
550         }
551         return _modules;
552     }
553 
554 
555     /***
556      * Sets the feed modules.
557      * <p>
558      * @param modules the list of ModuleImpl elements with the feed modules to set,
559      *        an empty list or <b>null</b> if none.
560      *
561      */
562     public void setModules(List modules) {
563         _modules = modules;
564     }
565 
566     /***
567      * Returns the module identified by a given URI.
568      * <p>
569      * @param uri the URI of the ModuleImpl.
570      * @return The module with the given URI, <b>null</b> if none.
571      */
572     public Module getModule(String uri) {
573         return ModuleUtils.getModule(getModules(),uri);
574     }
575 
576     /***
577      * Returns the Dublin Core module of the feed.
578      * @return the DC module, it's never <b>null</b>
579      *
580      */
581     private DCModule getDCModule() {
582         return (DCModule) getModule(DCModule.URI);
583     }
584 
585     public Class getInterface() {
586         return SyndFeed.class;
587     }
588 
589     public void copyFrom(Object obj) {
590         COPY_FROM_HELPER.copy(this,obj);
591     }
592 
593 
594     // TODO We need to find out how to refactor this one in a nice reusable way.
595 
596     private static final CopyFromHelper COPY_FROM_HELPER;
597 
598     static {
599         Map basePropInterfaceMap = new HashMap();
600         basePropInterfaceMap.put("feedType",String.class);
601         basePropInterfaceMap.put("encoding",String.class);
602         basePropInterfaceMap.put("uri",String.class);
603         basePropInterfaceMap.put("title",String.class);
604         basePropInterfaceMap.put("link",String.class);
605         basePropInterfaceMap.put("description",String.class);
606         basePropInterfaceMap.put("image",SyndImage.class);
607         basePropInterfaceMap.put("entries",SyndEntry.class);
608         basePropInterfaceMap.put("modules",Module.class);
609 
610         Map basePropClassImplMap = new HashMap();
611         basePropClassImplMap.put(SyndEntry.class,SyndEntryImpl.class);
612         basePropClassImplMap.put(SyndImage.class,SyndImageImpl.class);
613         basePropClassImplMap.put(DCModule.class,DCModuleImpl.class);
614         basePropClassImplMap.put(SyModule.class,SyModuleImpl.class);
615 
616         COPY_FROM_HELPER = new CopyFromHelper(SyndFeed.class,basePropInterfaceMap,basePropClassImplMap);
617     }
618 
619 }