1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
40 private ObjectBean _objBean;
41
42 private String _encoding;
43 private String _uri;
44 private SyndContent _title;
45 private SyndContent _description;
46 private String _feedType;
47 private String _link;
48 private List _links;
49 private SyndImage _image;
50 private List _entries;
51 private List _modules;
52 private List _authors;
53 private List _contributors;
54 private List _foreignMarkup;
55
56 private static final Converters CONVERTERS = new Converters();
57
58 private static final Set IGNORE_PROPERTIES = new HashSet();
59
60 /***
61 * Unmodifiable Set containing the convenience properties of this class.
62 * <p>
63 * Convenience properties are mapped to Modules, for cloning the convenience properties
64 * can be ignored as the will be copied as part of the module cloning.
65 */
66
67 public static final Set CONVENIENCE_PROPERTIES = Collections.unmodifiableSet(IGNORE_PROPERTIES);
68
69 static {
70 IGNORE_PROPERTIES.add("publishedDate");
71 IGNORE_PROPERTIES.add("author");
72 IGNORE_PROPERTIES.add("copyright");
73 IGNORE_PROPERTIES.add("categories");
74 IGNORE_PROPERTIES.add("language");
75 }
76
77 /***
78 * Returns the real feed types the SyndFeedImpl supports when converting from and to.
79 * <p>
80 * @return the real feed type supported.
81 */
82 public List getSupportedFeedTypes() {
83 return CONVERTERS.getSupportedFeedTypes();
84 }
85
86 /***
87 * For implementations extending SyndFeedImpl to be able to use the ObjectBean functionality
88 * with extended interfaces.
89 * <p>
90 * @param beanClass
91 * @param convenienceProperties set containing the convenience properties of the SyndEntryImpl
92 * (the are ignored during cloning, check CloneableBean for details).
93 *
94 */
95 protected SyndFeedImpl(Class beanClass,Set convenienceProperties) {
96 _objBean = new ObjectBean(beanClass,this,convenienceProperties);
97 }
98
99 /***
100 * Default constructor. All properties are set to <b>null</b>.
101 * <p>
102 *
103 */
104 public SyndFeedImpl() {
105 this(null);
106 }
107
108 /***
109 * Creates a SyndFeedImpl and populates all its properties out of the
110 * given RSS Channel or Atom Feed properties.
111 * <p>
112 * @param feed the RSS Channel or the Atom Feed to populate the properties from.
113 *
114 */
115 public SyndFeedImpl(WireFeed feed) {
116 this(SyndFeed.class,IGNORE_PROPERTIES);
117 if (feed!=null) {
118 _feedType = feed.getFeedType();
119 Converter converter = CONVERTERS.getConverter(_feedType);
120 if (converter==null) {
121 throw new IllegalArgumentException("Invalid feed type ["+_feedType+"]");
122 }
123 converter.copyInto(feed,this);
124 }
125 }
126
127 /***
128 * Creates a deep 'bean' clone of the object.
129 * <p>
130 * @return a clone of the object.
131 * @throws CloneNotSupportedException thrown if an element of the object cannot be cloned.
132 *
133 */
134 public Object clone() throws CloneNotSupportedException {
135 return _objBean.clone();
136 }
137
138 /***
139 * Indicates whether some other object is "equal to" this one as defined by the Object equals() method.
140 * <p>
141 * @param other he reference object with which to compare.
142 * @return <b>true</b> if 'this' object is equal to the 'other' object.
143 *
144 */
145 public boolean equals(Object other) {
146
147 Object fm = getForeignMarkup();
148 setForeignMarkup(((SyndFeedImpl)other).getForeignMarkup());
149 boolean ret = _objBean.equals(other);
150
151 setForeignMarkup(fm);
152 return ret;
153 }
154
155 /***
156 * Returns a hashcode value for the object.
157 * <p>
158 * It follows the contract defined by the Object hashCode() method.
159 * <p>
160 * @return the hashcode of the bean object.
161 *
162 */
163 public int hashCode() {
164 return _objBean.hashCode();
165 }
166
167 /***
168 * Returns the String representation for the object.
169 * <p>
170 * @return String representation for the object.
171 *
172 */
173 public String toString() {
174 return _objBean.toString();
175 }
176
177 /***
178 * Creates a real feed containing the information of the SyndFeedImpl.
179 * <p>
180 * The feed type of the created WireFeed is taken from the SyndFeedImpl feedType property.
181 * <p>
182 * @return the real feed.
183 *
184 */
185 public WireFeed createWireFeed() {
186 return createWireFeed(_feedType);
187 }
188
189 /***
190 * Creates a real feed containing the information of the SyndFeedImpl.
191 * <p>
192 * @param feedType the feed type for the WireFeed to be created.
193 * @return the real feed.
194 *
195 */
196 public WireFeed createWireFeed(String feedType) {
197 if (feedType==null) {
198 throw new IllegalArgumentException("Feed type cannot be null");
199 }
200 Converter converter = CONVERTERS.getConverter(feedType);
201 if (converter==null) {
202 throw new IllegalArgumentException("Invalid feed type ["+feedType+"]");
203 }
204 return converter.createRealFeed(this);
205 }
206
207 /***
208 * Returns the wire feed type the feed had/will-have when coverted from/to a WireFeed.
209 * <p>
210 * @return the feed type, <b>null</b> if none.
211 *
212 */
213 public String getFeedType() {
214 return _feedType;
215 }
216
217 /***
218 * Sets the wire feed type the feed will-have when coverted to a WireFeed.
219 * <p>
220 * @param feedType the feed type to set, <b>null</b> if none.
221 *
222 */
223 public void setFeedType(String feedType) {
224 _feedType = feedType;
225 }
226
227 /***
228 * Returns the charset encoding of a the feed. This is not set by Rome parsers.
229 * <p>
230 * @return the charset encoding of the feed.
231 *
232 */
233 public String getEncoding() {
234 return _encoding;
235 }
236
237 /***
238 * Sets the charset encoding of a the feed. This is not set by Rome parsers.
239 * <p>
240 * @param encoding the charset encoding of the feed.
241 *
242 */
243 public void setEncoding(String encoding) {
244 _encoding = encoding;
245 }
246
247 /***
248 * Returns the feed URI.
249 * <p>
250 * How the feed URI maps to a concrete feed type (RSS or Atom) depends on
251 * the concrete feed type. This is explained in detail in Rome documentation,
252 * <a href="http://wiki.java.net/bin/edit/Javawsxml/Rome04URIMapping">Feed and entry URI mapping</a>.
253 * <p>
254 * The returned URI is a normalized URI as specified in RFC 2396bis.
255 * <p>
256 * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is
257 * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link
258 * is the URL that the item is accessible under, the URI is the
259 * permanent identifier which the aggregator should use to reference
260 * this item. Often the URI will use some standardized identifier scheme
261 * such as DOI's so that items can be identified even if they appear in
262 * multiple feeds with different "links" (they might be on different
263 * hosting platforms but be the same item). Also, though rare, there
264 * could be multiple items with the same link but a different URI and
265 * associated metadata which need to be treated as distinct entities.
266 * In the RSS 1.0 case the URI must be a valid RDF URI reference.
267 * <p>
268 * @return the feed URI, <b>null</b> if none.
269 *
270 */
271 public String getUri() {
272 return _uri;
273 }
274
275 /***
276 * Sets the feed URI.
277 * <p>
278 * How the feed URI maps to a concrete feed type (RSS or Atom) depends on
279 * the concrete feed type. This is explained in detail in Rome documentation,
280 * <a href="http://wiki.java.net/bin/edit/Javawsxml/Rome04URIMapping">Feed and entry URI mapping</a>.
281 * <p>
282 * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is
283 * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link
284 * is the URL that the item is accessible under, the URI is the
285 * permanent identifier which the aggregator should use to reference
286 * this item. Often the URI will use some standardized identifier scheme
287 * such as DOI's so that items can be identified even if they appear in
288 * multiple feeds with different "links" (they might be on different
289 * hosting platforms but be the same item). Also, though rare, there
290 * could be multiple items with the same link but a different URI and
291 * associated metadata which need to be treated as distinct entities.
292 * In the RSS 1.0 case the URI must be a valid RDF URI reference.
293 * <p>
294 * @param uri the feed URI to set, <b>null</b> if none.
295 *
296 */
297 public void setUri(String uri) {
298 _uri = URINormalizer.normalize(uri);
299 }
300
301 /***
302 * Returns the feed title.
303 * <p>
304 * @return the feed title, <b>null</b> if none.
305 *
306 */
307 public String getTitle() {
308 if (_title != null) return _title.getValue();
309 return null;
310 }
311
312 /***
313 * Sets the feed title.
314 * <p>
315 * @param title the feed title to set, <b>null</b> if none.
316 *
317 */
318 public void setTitle(String title) {
319 if (_title == null) _title = new SyndContentImpl();
320 _title.setValue(title);
321 }
322
323 /***
324 * Returns the feed title as a text construct.
325 * <p>
326 * @return the feed title, <b>null</b> if none.
327 *
328 */
329 public SyndContent getTitleEx() {
330 return _title;
331 }
332
333 /***
334 * Sets the feed title as a text construct.
335 * <p>
336 * @param title the feed title to set, <b>null</b> if none.
337 *
338 */
339 public void setTitleEx(SyndContent title) {
340 _title = title;
341 }
342
343 /***
344 * Returns the feed link.
345 * <p>
346 * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is
347 * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link
348 * is the URL that the item is accessible under, the URI is the
349 * permanent identifier which the aggregator should use to reference
350 * this item. Often the URI will use some standardized identifier scheme
351 * such as DOI's so that items can be identified even if they appear in
352 * multiple feeds with different "links" (they might be on different
353 * hosting platforms but be the same item). Also, though rare, there
354 * could be multiple items with the same link but a different URI and
355 * associated metadata which need to be treated as distinct entities.
356 * In the RSS 1.0 case the URI must be a valid RDF URI reference.
357 * <p>
358 * @return the feed link, <b>null</b> if none.
359 *
360 */
361 public String getLink() {
362 return _link;
363 }
364
365 /***
366 * Sets the feed link.
367 * <p>
368 * Note: The URI is the unique identifier, in the RSS 2.0/atom case this is
369 * the GUID, for RSS 1.0 this is the URI attribute of the item. The Link
370 * is the URL that the item is accessible under, the URI is the
371 * permanent identifier which the aggregator should use to reference
372 * this item. Often the URI will use some standardized identifier scheme
373 * such as DOI's so that items can be identified even if they appear in
374 * multiple feeds with different "links" (they might be on different
375 * hosting platforms but be the same item). Also, though rare, there
376 * could be multiple items with the same link but a different URI and
377 * associated metadata which need to be treated as distinct entities.
378 * In the RSS 1.0 case the URI must be a valid RDF URI reference.
379 * <p>
380 * @param link the feed link to set, <b>null</b> if none.
381 *
382 */
383 public void setLink(String link) {
384 _link = link;
385 }
386
387 /***
388 * Returns the feed description.
389 * <p>
390 * @return the feed description, <b>null</b> if none.
391 *
392 */
393 public String getDescription() {
394 if (_description != null) return _description.getValue();
395 return null;
396 }
397
398 /***
399 * Sets the feed description.
400 * <p>
401 * @param description the feed description to set, <b>null</b> if none.
402 *
403 */
404 public void setDescription(String description) {
405 if (_description == null) _description = new SyndContentImpl();
406 _description.setValue(description);
407 }
408
409 /***
410 * Returns the feed description as a text construct.
411 * <p>
412 * @return the feed description, <b>null</b> if none.
413 *
414 */
415 public SyndContent getDescriptionEx() {
416 return _description;
417 }
418
419 /***
420 * Sets the feed description as a text construct.
421 * <p>
422 * @param description the feed description to set, <b>null</b> if none.
423 *
424 */
425 public void setDescriptionEx(SyndContent description) {
426 _description = description;
427 }
428
429 /***
430 * Returns the feed published date.
431 * <p>
432 * This method is a convenience method, it maps to the Dublin Core module date.
433 * <p>
434 * @return the feed published date, <b>null</b> if none.
435 *
436 */
437 public Date getPublishedDate() {
438 return getDCModule().getDate();
439 }
440
441 /***
442 * Sets the feed published date.
443 * <p>
444 * This method is a convenience method, it maps to the Dublin Core module date.
445 * <p>
446 * @param publishedDate the feed published date to set, <b>null</b> if none.
447 *
448 */
449 public void setPublishedDate(Date publishedDate) {
450 getDCModule().setDate(publishedDate);
451 }
452
453 /***
454 * Returns the feed copyright.
455 * <p>
456 * This method is a convenience method, it maps to the Dublin Core module rights.
457 * <p>
458 * @return the feed copyright, <b>null</b> if none.
459 *
460 */
461 public String getCopyright() {
462 return getDCModule().getRights();
463 }
464
465 /***
466 * Sets the feed copyright.
467 * <p>
468 * This method is a convenience method, it maps to the Dublin Core module rights.
469 * <p>
470 * @param copyright the feed copyright to set, <b>null</b> if none.
471 *
472 */
473 public void setCopyright(String copyright) {
474 getDCModule().setRights(copyright);
475 }
476
477 /***
478 * Returns the feed image.
479 * <p>
480 * @return the feed image, <b>null</b> if none.
481 *
482 */
483 public SyndImage getImage() {
484 return _image;
485 }
486
487 /***
488 * Sets the feed image.
489 * <p>
490 * @param image the feed image to set, <b>null</b> if none.
491 *
492 */
493 public void setImage(SyndImage image) {
494 _image = image;
495 }
496
497 /***
498 * Returns the feed categories.
499 * <p>
500 * This method is a convenience method, it maps to the Dublin Core module subjects.
501 * <p>
502 * @return a list of SyndCategoryImpl elements with the feed categories,
503 * an empty list if none.
504 *
505 */
506 public List getCategories() {
507 return new SyndCategoryListFacade(getDCModule().getSubjects());
508 }
509
510 /***
511 * Sets the feed categories.
512 * <p>
513 * This method is a convenience method, it maps to the Dublin Core module subjects.
514 * <p>
515 * @param categories the list of SyndCategoryImpl elements with the feed categories to set,
516 * an empty list or <b>null</b> if none.
517 *
518 */
519 public void setCategories(List categories) {
520 getDCModule().setSubjects(SyndCategoryListFacade.convertElementsSyndCategoryToSubject(categories));
521 }
522
523 /***
524 * Returns the feed entries.
525 * <p>
526 * @return a list of SyndEntryImpl elements with the feed entries,
527 * an empty list if none.
528 *
529 */
530 public List getEntries() {
531 return (_entries==null) ? (_entries=new ArrayList()) : _entries;
532 }
533
534 /***
535 * Sets the feed entries.
536 * <p>
537 * @param entries the list of SyndEntryImpl elements with the feed entries to set,
538 * an empty list or <b>null</b> if none.
539 *
540 */
541 public void setEntries(List entries) {
542 _entries = entries;
543 }
544
545 /***
546 * Returns the feed language.
547 * <p>
548 * This method is a convenience method, it maps to the Dublin Core module language.
549 * <p>
550 * @return the feed language, <b>null</b> if none.
551 *
552 */
553 public String getLanguage() {
554 return getDCModule().getLanguage();
555 }
556
557 /***
558 * Sets the feed language.
559 * <p>
560 * This method is a convenience method, it maps to the Dublin Core module language.
561 * <p>
562 * @param language the feed language to set, <b>null</b> if none.
563 *
564 */
565 public void setLanguage(String language) {
566 getDCModule().setLanguage(language);
567 }
568
569 /***
570 * Returns the feed modules.
571 * <p>
572 * @return a list of ModuleImpl elements with the feed modules,
573 * an empty list if none.
574 *
575 */
576 public List getModules() {
577 if (_modules==null) {
578 _modules=new ArrayList();
579 }
580 if (ModuleUtils.getModule(_modules,DCModule.URI)==null) {
581 _modules.add(new DCModuleImpl());
582 }
583 return _modules;
584 }
585
586
587 /***
588 * Sets the feed modules.
589 * <p>
590 * @param modules the list of ModuleImpl elements with the feed modules to set,
591 * an empty list or <b>null</b> if none.
592 *
593 */
594 public void setModules(List modules) {
595 _modules = modules;
596 }
597
598 /***
599 * Returns the module identified by a given URI.
600 * <p>
601 * @param uri the URI of the ModuleImpl.
602 * @return The module with the given URI, <b>null</b> if none.
603 */
604 public Module getModule(String uri) {
605 return ModuleUtils.getModule(getModules(),uri);
606 }
607
608 /***
609 * Returns the Dublin Core module of the feed.
610 * @return the DC module, it's never <b>null</b>
611 *
612 */
613 private DCModule getDCModule() {
614 return (DCModule) getModule(DCModule.URI);
615 }
616
617 public Class getInterface() {
618 return SyndFeed.class;
619 }
620
621 public void copyFrom(Object obj) {
622 COPY_FROM_HELPER.copy(this,obj);
623 }
624
625
626
627
628 private static final CopyFromHelper COPY_FROM_HELPER;
629
630 static {
631 Map basePropInterfaceMap = new HashMap();
632 basePropInterfaceMap.put("feedType",String.class);
633 basePropInterfaceMap.put("encoding",String.class);
634 basePropInterfaceMap.put("uri",String.class);
635 basePropInterfaceMap.put("title",String.class);
636 basePropInterfaceMap.put("link",String.class);
637 basePropInterfaceMap.put("description",String.class);
638 basePropInterfaceMap.put("image",SyndImage.class);
639 basePropInterfaceMap.put("entries",SyndEntry.class);
640 basePropInterfaceMap.put("modules",Module.class);
641
642 Map basePropClassImplMap = new HashMap();
643 basePropClassImplMap.put(SyndEntry.class,SyndEntryImpl.class);
644 basePropClassImplMap.put(SyndImage.class,SyndImageImpl.class);
645 basePropClassImplMap.put(DCModule.class,DCModuleImpl.class);
646 basePropClassImplMap.put(SyModule.class,SyModuleImpl.class);
647
648 COPY_FROM_HELPER = new CopyFromHelper(SyndFeed.class,basePropInterfaceMap,basePropClassImplMap);
649 }
650
651 /***
652 * Returns the links
653 * <p>
654 * @return Returns the links.
655 */
656 public List getLinks() {
657 return _links;
658 }
659
660 /***
661 * Set the links
662 * <p>
663 * @param links The links to set.
664 */
665 public void setLinks(List links) {
666 _links = links;
667 }
668
669 public List getAuthors() {
670 return _authors;
671 }
672
673 public void setAuthors(List authors) {
674 this._authors = authors;
675 }
676
677 /***
678 * Returns the feed author.
679 * <p>
680 * This method is a convenience method, it maps to the Dublin Core module creator.
681 * <p>
682 * @return the feed author, <b>null</b> if none.
683 *
684 */
685 public String getAuthor() {
686 return getDCModule().getCreator();
687 }
688
689 /***
690 * Sets the feed author.
691 * <p>
692 * This method is a convenience method, it maps to the Dublin Core module creator.
693 * <p>
694 * @param author the feed author to set, <b>null</b> if none.
695 *
696 */
697 public void setAuthor(String author) {
698 getDCModule().setCreator(author);
699 }
700
701 public List getContributors() {
702 return _contributors;
703 }
704
705 public void setContributors(List contributors) {
706 this._contributors = contributors;
707 }
708
709 /***
710 * Returns foreign markup found at channel level.
711 * <p>
712 * @return Opaque object to discourage use
713 *
714 */
715 public Object getForeignMarkup() {
716 return (_foreignMarkup==null) ? (_foreignMarkup=new ArrayList()) : _foreignMarkup;
717 }
718
719 /***
720 * Sets foreign markup found at channel level.
721 * <p>
722 * @param foreignMarkup Opaque object to discourage use
723 *
724 */
725 public void setForeignMarkup(Object foreignMarkup) {
726 _foreignMarkup = (List)foreignMarkup;
727 }
728 }