001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.bean.atom;
018
019import static org.apache.juneau.xml.annotation.XmlFormat.*;
020
021import java.util.*;
022
023import org.apache.juneau.annotation.*;
024import org.apache.juneau.xml.annotation.*;
025
026/**
027 * Represents a top-level Atom feed document.
028 *
029 * <p>
030 * An Atom feed is a Web resource that contains metadata and optionally a set of entries.
031 * Feeds are the top-level container element in Atom documents and act as a manifest of metadata
032 * and data associated with a collection of related resources.
033 *
034 * <p>
035 * The feed is the fundamental unit of syndication in Atom and is used to aggregate entries that
036 * share a common purpose, such as a blog, podcast channel, or news source.
037 *
038 * <h5 class='figure'>Schema</h5>
039 * <p class='bschema'>
040 *    atomFeed =
041 *       element atom:feed {
042 *          atomCommonAttributes,
043 *          (atomAuthor*
044 *           &amp; atomCategory*
045 *           &amp; atomContributor*
046 *           &amp; atomGenerator?
047 *           &amp; atomIcon?
048 *           &amp; atomId
049 *           &amp; atomLink*
050 *           &amp; atomLogo?
051 *           &amp; atomRights?
052 *           &amp; atomSubtitle?
053 *           &amp; atomTitle
054 *           &amp; atomUpdated
055 *           &amp; extensionElement*),
056 *          atomEntry*
057 *       }
058 * </p>
059 *
060 * <h5 class='section'>Required Elements:</h5>
061 * <p>
062 * Per RFC 4287, the following elements are required in a feed:
063 * <ul class='spaced-list'>
064 *    <li><c>atom:id</c> - A permanent, universally unique identifier for the feed.
065 *    <li><c>atom:title</c> - A human-readable title for the feed.
066 *    <li><c>atom:updated</c> - The most recent instant in time when the feed was modified.
067 * </ul>
068 *
069 * <h5 class='section'>Recommended Elements:</h5>
070 * <p>
071 * The following elements are recommended but not required:
072 * <ul class='spaced-list'>
073 *    <li><c>atom:author</c> - Authors of the feed (required if entries don't have authors).
074 *    <li><c>atom:link</c> - Links associated with the feed (should include a "self" link).
075 * </ul>
076 *
077 * <h5 class='section'>Example:</h5>
078 * <p class='bjava'>
079 *    <jc>// Create a feed using fluent-style setters</jc>
080 *    Feed <jv>feed</jv> = <jk>new</jk> Feed(
081 *       <js>"tag:example.org,2024:feed"</js>,
082 *       <js>"Example Feed"</js>,
083 *       <js>"2024-01-15T12:00:00Z"</js>
084 *    )
085 *    .setSubtitle(<js>"A sample Atom feed"</js>)
086 *    .setLinks(
087 *       <jk>new</jk> Link(<js>"self"</js>, <js>"application/atom+xml"</js>, <js>"http://example.org/feed.atom"</js>),
088 *       <jk>new</jk> Link(<js>"alternate"</js>, <js>"text/html"</js>, <js>"http://example.org"</js>)
089 *    )
090 *    .setAuthors(
091 *       <jk>new</jk> Person(<js>"John Doe"</js>).setEmail(<js>"john@example.org"</js>)
092 *    )
093 *    .setEntries(
094 *       <jk>new</jk> Entry(<js>"tag:example.org,2024:entry1"</js>, <js>"First Post"</js>, <js>"2024-01-15T12:00:00Z"</js>)
095 *          .setSummary(<js>"This is the first post"</js>)
096 *    );
097 *
098 *    <jc>// Serialize to ATOM/XML</jc>
099 *    String <jv>atomXml</jv> = XmlSerializer.<jsf>DEFAULT_SQ_READABLE</jsf>.serialize(<jv>feed</jv>);
100 * </p>
101 *
102 * <h5 class='section'>Specification:</h5>
103 * <p>
104 * Represents an <c>atomFeed</c> construct in the
105 * <a class="doclink" href="https://tools.ietf.org/html/rfc4287#section-4.1.1">RFC 4287 - Section 4.1.1</a> specification.
106 *
107 * <h5 class='section'>See Also:</h5><ul>
108 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanAtom">juneau-bean-atom</a>
109 *    <li class='extlink'><a class="doclink" href="https://tools.ietf.org/html/rfc4287">RFC 4287 - The Atom Syndication Format</a>
110 * </ul>
111 */
112@Bean(typeName = "feed")
113public class Feed extends CommonEntry {
114
115   // @formatter:off
116   private Generator generator;  // atomGenerator?
117   private Icon icon;            // atomIcon?
118   private Logo logo;            // atomLogo?
119   private Text subtitle;        // atomSubtitle?
120   private Entry[] entries;      // atomEntry*
121   // @formatter:on
122
123   /** Bean constructor. */
124   public Feed() {}
125
126   /**
127    * Normal constructor.
128    *
129    * @param id The feed identifier.
130    * @param title The feed title.
131    * @param updated The feed updated timestamp.
132    */
133   public Feed(Id id, Text title, Calendar updated) {
134      super(id, title, updated);
135   }
136
137   /**
138    * Normal constructor.
139    *
140    * @param id The feed identifier.
141    * @param title The feed title.
142    * @param updated The feed updated timestamp.
143    */
144   public Feed(String id, String title, String updated) {
145      super(id, title, updated);
146   }
147
148   /**
149    * Bean property getter:  <property>entries</property>.
150    *
151    * <p>
152    * Returns the individual entries contained within this feed.
153    *
154    * <p>
155    * Each entry represents a single item in the feed, such as a blog post, news article,
156    * podcast episode, or other discrete piece of content. Entries contain their own metadata
157    * including title, content, links, and timestamps.
158    *
159    * @return The property value, or <jk>null</jk> if it is not set.
160    */
161   @Xml(format = COLLAPSED)
162   public Entry[] getEntries() { return entries; }
163
164   /**
165    * Bean property getter:  <property>generator</property>.
166    *
167    * <p>
168    * Identifies the software agent used to generate the feed.
169    *
170    * <p>
171    * This is useful for debugging and analytics purposes, allowing consumers to identify the
172    * software responsible for producing the feed.
173    *
174    * @return The property value, or <jk>null</jk> if it is not set.
175    */
176   public Generator getGenerator() { return generator; }
177
178   /**
179    * Bean property getter:  <property>icon</property>.
180    *
181    * <p>
182    * Identifies a small image that provides iconic visual identification for the feed.
183    *
184    * <p>
185    * Icons should be square and small (typically 16x16 or similar). The image should have an
186    * aspect ratio of 1 (horizontal) to 1 (vertical).
187    *
188    * @return The property value, or <jk>null</jk> if it is not set.
189    */
190   public Icon getIcon() { return icon; }
191
192   /**
193    * Bean property getter:  <property>logo</property>.
194    *
195    * <p>
196    * Identifies a larger image that provides visual identification for the feed.
197    *
198    * <p>
199    * Logos should be twice as wide as they are tall (aspect ratio of 2:1).
200    *
201    * @return The property value, or <jk>null</jk> if it is not set.
202    */
203   public Logo getLogo() { return logo; }
204
205   /**
206    * Bean property getter:  <property>subtitle</property>.
207    *
208    * <p>
209    * Returns a human-readable description or subtitle for the feed.
210    *
211    * <p>
212    * The subtitle provides additional context about the feed's purpose or content beyond
213    * what is conveyed in the title.
214    *
215    * @return The property value, or <jk>null</jk> if it is not set.
216    */
217   public Text getSubtitle() { return subtitle; }
218
219   @Override /* Overridden from CommonEntry */
220   public Feed setAuthors(Person...value) {
221      super.setAuthors(value);
222      return this;
223   }
224
225   @Override /* Overridden from Common */
226   public Feed setBase(Object value) {
227      super.setBase(value);
228      return this;
229   }
230
231   @Override /* Overridden from CommonEntry */
232   public Feed setCategories(Category...value) {
233      super.setCategories(value);
234      return this;
235   }
236
237   @Override /* Overridden from CommonEntry */
238   public Feed setContributors(Person...value) {
239      super.setContributors(value);
240      return this;
241   }
242
243   /**
244    * Bean property setter:  <property>entries</property>.
245    *
246    * <p>
247    * Sets the individual entries contained within this feed.
248    *
249    * <h5 class='section'>Example:</h5>
250    * <p class='bjava'>
251    *    Feed <jv>feed</jv> = <jk>new</jk> Feed(...)
252    *       .setEntries(
253    *          <jk>new</jk> Entry(
254    *             <js>"tag:example.org,2024:entry1"</js>,
255    *             <js>"First Post"</js>,
256    *             <js>"2024-01-15T12:00:00Z"</js>
257    *          )
258    *          .setContent(
259    *             <jk>new</jk> Content(<js>"html"</js>)
260    *                .setText(<js>"&lt;p&gt;This is the content&lt;/p&gt;"</js>)
261    *          ),
262    *          <jk>new</jk> Entry(
263    *             <js>"tag:example.org,2024:entry2"</js>,
264    *             <js>"Second Post"</js>,
265    *             <js>"2024-01-16T12:00:00Z"</js>
266    *          )
267    *       );
268    * </p>
269    *
270    * @param value
271    *    The new value for this property.
272    *    <br>Can be <jk>null</jk> to unset the property.
273    * @return This object.
274    */
275   public Feed setEntries(Entry...value) {
276      entries = value;
277      return this;
278   }
279
280   /**
281    * Bean property setter:  <property>generator</property>.
282    *
283    * <p>
284    * Identifies the software agent used to generate the feed.
285    *
286    * <h5 class='section'>Example:</h5>
287    * <p class='bjava'>
288    *    Feed <jv>feed</jv> = <jk>new</jk> Feed(...)
289    *       .setGenerator(
290    *          <jk>new</jk> Generator(<js>"My Blog Software"</js>)
291    *             .setUri(<js>"http://www.example.com/software"</js>)
292    *             .setVersion(<js>"2.0"</js>)
293    *       );
294    * </p>
295    *
296    * @param value
297    *    The new value for this property.
298    *    <br>Can be <jk>null</jk> to unset the property.
299    * @return This object.
300    */
301   public Feed setGenerator(Generator value) {
302      generator = value;
303      return this;
304   }
305
306   /**
307    * Bean property setter:  <property>icon</property>.
308    *
309    * <p>
310    * Identifies a small image that provides iconic visual identification for the feed.
311    *
312    * <h5 class='section'>Example:</h5>
313    * <p class='bjava'>
314    *    Feed <jv>feed</jv> = <jk>new</jk> Feed(...)
315    *       .setIcon(<jk>new</jk> Icon(<js>"http://example.org/icon.png"</js>));
316    * </p>
317    *
318    * @param value
319    *    The new value for this property.
320    *    <br>Can be <jk>null</jk> to unset the property.
321    * @return This object.
322    */
323   public Feed setIcon(Icon value) {
324      icon = value;
325      return this;
326   }
327
328   @Override /* Overridden from CommonEntry */
329   public Feed setId(Id value) {
330      super.setId(value);
331      return this;
332   }
333
334   @Override /* Overridden from CommonEntry */
335   public Feed setId(String value) {
336      super.setId(value);
337      return this;
338   }
339
340   @Override /* Overridden from Common */
341   public Feed setLang(String value) {
342      super.setLang(value);
343      return this;
344   }
345
346   @Override /* Overridden from CommonEntry */
347   public Feed setLinks(Link...value) {
348      super.setLinks(value);
349      return this;
350   }
351
352   /**
353    * Bean property setter:  <property>logo</property>.
354    *
355    * <p>
356    * Identifies a larger image that provides visual identification for the feed.
357    *
358    * <h5 class='section'>Example:</h5>
359    * <p class='bjava'>
360    *    Feed <jv>feed</jv> = <jk>new</jk> Feed(...)
361    *       .setLogo(<jk>new</jk> Logo(<js>"http://example.org/logo.png"</js>));
362    * </p>
363    *
364    * @param value
365    *    The new value for this property.
366    *    <br>Can be <jk>null</jk> to unset the property.
367    * @return This object.
368    */
369   public Feed setLogo(Logo value) {
370      logo = value;
371      return this;
372   }
373
374   @Override /* Overridden from CommonEntry */
375   public Feed setRights(String value) {
376      super.setRights(value);
377      return this;
378   }
379
380   @Override /* Overridden from CommonEntry */
381   public Feed setRights(Text value) {
382      super.setRights(value);
383      return this;
384   }
385
386   /**
387    * Bean property fluent setter:  <property>subtitle</property>.
388    *
389    * <p>
390    * Sets a human-readable description or subtitle for the feed as plain text.
391    *
392    * @param value
393    *    The new value for this property.
394    *    <br>Can be <jk>null</jk> to unset the property.
395    * @return This object.
396    */
397   public Feed setSubtitle(String value) {
398      setSubtitle(new Text(value));
399      return this;
400   }
401
402   /**
403    * Bean property setter:  <property>subtitle</property>.
404    *
405    * <p>
406    * Sets a human-readable description or subtitle for the feed.
407    *
408    * <h5 class='section'>Example:</h5>
409    * <p class='bjava'>
410    *    Feed <jv>feed</jv> = <jk>new</jk> Feed(...)
411    *       .setSubtitle(
412    *          <jk>new</jk> Text(<js>"html"</js>)
413    *             .setText(<js>"A &lt;em&gt;comprehensive&lt;/em&gt; guide to Atom feeds"</js>)
414    *       );
415    * </p>
416    *
417    * @param value
418    *    The new value for this property.
419    *    <br>Can be <jk>null</jk> to unset the property.
420    * @return This object.
421    */
422   public Feed setSubtitle(Text value) {
423      subtitle = value;
424      return this;
425   }
426
427   @Override /* Overridden from CommonEntry */
428   public Feed setTitle(String value) {
429      super.setTitle(value);
430      return this;
431   }
432
433   @Override /* Overridden from CommonEntry */
434   public Feed setTitle(Text value) {
435      super.setTitle(value);
436      return this;
437   }
438
439   @Override /* Overridden from CommonEntry */
440   public Feed setUpdated(Calendar value) {
441      super.setUpdated(value);
442      return this;
443   }
444
445   @Override /* Overridden from CommonEntry */
446   public Feed setUpdated(String value) {
447      super.setUpdated(value);
448      return this;
449   }
450}