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