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 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
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 }