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.commons.utils.Shorts.*; 020import static org.apache.juneau.marshall.xml.XmlFormat.*; 021 022import java.util.*; 023 024import org.apache.juneau.marshall.*; 025import org.apache.juneau.marshall.xml.*; 026 027/** 028 * Represents a top-level Atom feed document. 029 * 030 * <p> 031 * An Atom feed is a Web resource that contains metadata and optionally a set of entries. 032 * Feeds are the top-level container element in Atom documents and act as a manifest of metadata 033 * and data associated with a collection of related resources. 034 * 035 * <p> 036 * The feed is the fundamental unit of syndication in Atom and is used to aggregate entries that 037 * share a common purpose, such as a blog, podcast channel, or news source. 038 * 039 * <h5 class='figure'>Schema</h5> 040 * <p class='bschema'> 041 * atomFeed = 042 * element atom:feed { 043 * atomCommonAttributes, 044 * (atomAuthor* 045 * & atomCategory* 046 * & atomContributor* 047 * & atomGenerator? 048 * & atomIcon? 049 * & atomId 050 * & atomLink* 051 * & atomLogo? 052 * & atomRights? 053 * & atomSubtitle? 054 * & atomTitle 055 * & atomUpdated 056 * & extensionElement*), 057 * atomEntry* 058 * } 059 * </p> 060 * 061 * <h5 class='section'>Required Elements:</h5> 062 * <p> 063 * Per RFC 4287, the following elements are required in a feed: 064 * <ul class='spaced-list'> 065 * <li><c>atom:id</c> - A permanent, universally unique identifier for the feed. 066 * <li><c>atom:title</c> - A human-readable title for the feed. 067 * <li><c>atom:updated</c> - The most recent instant in time when the feed was modified. 068 * </ul> 069 * 070 * <h5 class='section'>Recommended Elements:</h5> 071 * <p> 072 * The following elements are recommended but not required: 073 * <ul class='spaced-list'> 074 * <li><c>atom:author</c> - Authors of the feed (required if entries don't have authors). 075 * <li><c>atom:link</c> - Links associated with the feed (should include a "self" link). 076 * </ul> 077 * 078 * <h5 class='section'>Example:</h5> 079 * <p class='bjava'> 080 * <jc>// Create a feed using fluent-style setters</jc> 081 * Feed <jv>feed</jv> = <jk>new</jk> Feed( 082 * <js>"tag:example.org,2024:feed"</js>, 083 * <js>"Example Feed"</js>, 084 * <js>"2024-01-15T12:00:00Z"</js> 085 * ) 086 * .setSubtitle(<js>"A sample Atom feed"</js>) 087 * .setLinks( 088 * <jk>new</jk> Link(<js>"self"</js>, <js>"application/atom+xml"</js>, <js>"http://example.org/feed.atom"</js>), 089 * <jk>new</jk> Link(<js>"alternate"</js>, <js>"text/html"</js>, <js>"http://example.org"</js>) 090 * ) 091 * .setAuthors( 092 * <jk>new</jk> Person(<js>"John Doe"</js>).setEmail(<js>"john@example.org"</js>) 093 * ) 094 * .setEntries( 095 * <jk>new</jk> Entry(<js>"tag:example.org,2024:entry1"</js>, <js>"First Post"</js>, <js>"2024-01-15T12:00:00Z"</js>) 096 * .setSummary(<js>"This is the first post"</js>) 097 * ); 098 * 099 * <jc>// Serialize to ATOM/XML</jc> 100 * String <jv>atomXml</jv> = XmlSerializer.<jsf>DEFAULT_SQ_READABLE</jsf>.write(<jv>feed</jv>); 101 * </p> 102 * 103 * <h5 class='section'>Specification:</h5> 104 * <p> 105 * Represents an <c>atomFeed</c> construct in the 106 * <a class="doclink" href="https://tools.ietf.org/html/rfc4287#section-4.1.1">RFC 4287 - Section 4.1.1</a> specification. 107 * 108 * <h5 class='section'>See Also:</h5><ul> 109 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanAtom">juneau-bean-atom</a> 110 * <li class='extlink'><a class="doclink" href="https://tools.ietf.org/html/rfc4287">RFC 4287 - The Atom Syndication Format</a> 111 * </ul> 112 */ 113@Marshalled(typeName = "feed") 114public class Feed extends CommonEntry<Feed> { 115 116 // @formatter:off 117 private Generator generator; // atomGenerator? 118 private Icon icon; // atomIcon? 119 private Logo logo; // atomLogo? 120 private Text subtitle; // atomSubtitle? 121 private Entry[] entries; // atomEntry* 122 // @formatter:on 123 124 /** Bean constructor. */ 125 public Feed() {} 126 127 /** 128 * Normal constructor. 129 * 130 * @param id The feed identifier. Can be <jk>null</jk> to leave the property unset. 131 * @param title The feed title. Can be <jk>null</jk> to leave the property unset. 132 * @param updated The feed updated timestamp. Can be <jk>null</jk> to leave the property unset. 133 */ 134 public Feed(Id id, Text title, Calendar updated) { 135 super(id, title, updated); 136 } 137 138 /** 139 * Normal constructor. 140 * 141 * @param id The feed identifier. Can be <jk>null</jk>, in which case the property is set to an {@link Id} with no text (not left unset). 142 * @param title The feed title. Can be <jk>null</jk>, in which case the property is set to a {@link Text} with no text (not left unset). 143 * @param updated The feed updated timestamp. Can be <jk>null</jk> or blank to leave the property unset. 144 */ 145 public Feed(String id, String title, String updated) { 146 super(id, title, updated); 147 } 148 149 /** 150 * Bean property getter: <property>entries</property>. 151 * 152 * <p> 153 * Returns the individual entries contained within this feed. 154 * 155 * <p> 156 * Each entry represents a single item in the feed, such as a blog post, news article, 157 * podcast episode, or other discrete piece of content. Entries contain their own metadata 158 * including title, content, links, and timestamps. 159 * 160 * @return The property value, or <jk>null</jk> if it is not set. 161 */ 162 @Xml(format = COLLAPSED) 163 public Entry[] getEntries() { return cp(entries); } 164 165 /** 166 * Bean property getter: <property>generator</property>. 167 * 168 * <p> 169 * Identifies the software agent used to generate the feed. 170 * 171 * <p> 172 * This is useful for debugging and analytics purposes, allowing consumers to identify the 173 * software responsible for producing the feed. 174 * 175 * @return The property value, or <jk>null</jk> if it is not set. 176 */ 177 public Generator getGenerator() { return generator; } 178 179 /** 180 * Bean property getter: <property>icon</property>. 181 * 182 * <p> 183 * Identifies a small image that provides iconic visual identification for the feed. 184 * 185 * <p> 186 * Icons should be square and small (typically 16x16 or similar). The image should have an 187 * aspect ratio of 1 (horizontal) to 1 (vertical). 188 * 189 * @return The property value, or <jk>null</jk> if it is not set. 190 */ 191 public Icon getIcon() { return icon; } 192 193 /** 194 * Bean property getter: <property>logo</property>. 195 * 196 * <p> 197 * Identifies a larger image that provides visual identification for the feed. 198 * 199 * <p> 200 * Logos should be twice as wide as they are tall (aspect ratio of 2:1). 201 * 202 * @return The property value, or <jk>null</jk> if it is not set. 203 */ 204 public Logo getLogo() { return logo; } 205 206 /** 207 * Bean property getter: <property>subtitle</property>. 208 * 209 * <p> 210 * Returns a human-readable description or subtitle for the feed. 211 * 212 * <p> 213 * The subtitle provides additional context about the feed's purpose or content beyond 214 * what is conveyed in the title. 215 * 216 * @return The property value, or <jk>null</jk> if it is not set. 217 */ 218 public Text getSubtitle() { return subtitle; } 219 220 /** 221 * Bean property setter: <property>entries</property>. 222 * 223 * <p> 224 * Sets the individual entries contained within this feed. 225 * 226 * <h5 class='section'>Example:</h5> 227 * <p class='bjava'> 228 * Feed <jv>feed</jv> = <jk>new</jk> Feed(...) 229 * .setEntries( 230 * <jk>new</jk> Entry( 231 * <js>"tag:example.org,2024:entry1"</js>, 232 * <js>"First Post"</js>, 233 * <js>"2024-01-15T12:00:00Z"</js> 234 * ) 235 * .setContent( 236 * <jk>new</jk> Content(<js>"html"</js>) 237 * .setText(<js>"<p>This is the content</p>"</js>) 238 * ), 239 * <jk>new</jk> Entry( 240 * <js>"tag:example.org,2024:entry2"</js>, 241 * <js>"Second Post"</js>, 242 * <js>"2024-01-16T12:00:00Z"</js> 243 * ) 244 * ); 245 * </p> 246 * 247 * @param value 248 * The new value for this property. 249 * <br>Can be <jk>null</jk> to unset the property. 250 * @return This object. 251 */ 252 public Feed setEntries(Entry...value) { 253 entries = cp(value); 254 return this; 255 } 256 257 /** 258 * Bean property setter: <property>generator</property>. 259 * 260 * <p> 261 * Identifies the software agent used to generate the feed. 262 * 263 * <h5 class='section'>Example:</h5> 264 * <p class='bjava'> 265 * Feed <jv>feed</jv> = <jk>new</jk> Feed(...) 266 * .setGenerator( 267 * <jk>new</jk> Generator(<js>"My Blog Software"</js>) 268 * .setUri(<js>"http://www.example.com/software"</js>) 269 * .setVersion(<js>"2.0"</js>) 270 * ); 271 * </p> 272 * 273 * @param value 274 * The new value for this property. 275 * <br>Can be <jk>null</jk> to unset the property. 276 * @return This object. 277 */ 278 public Feed setGenerator(Generator value) { 279 generator = value; 280 return this; 281 } 282 283 /** 284 * Bean property setter: <property>icon</property>. 285 * 286 * <p> 287 * Identifies a small image that provides iconic visual identification for the feed. 288 * 289 * <h5 class='section'>Example:</h5> 290 * <p class='bjava'> 291 * Feed <jv>feed</jv> = <jk>new</jk> Feed(...) 292 * .setIcon(<jk>new</jk> Icon(<js>"http://example.org/icon.png"</js>)); 293 * </p> 294 * 295 * @param value 296 * The new value for this property. 297 * <br>Can be <jk>null</jk> to unset the property. 298 * @return This object. 299 */ 300 public Feed setIcon(Icon value) { 301 icon = value; 302 return this; 303 } 304 305 /** 306 * Bean property setter: <property>logo</property>. 307 * 308 * <p> 309 * Identifies a larger image that provides visual identification for the feed. 310 * 311 * <h5 class='section'>Example:</h5> 312 * <p class='bjava'> 313 * Feed <jv>feed</jv> = <jk>new</jk> Feed(...) 314 * .setLogo(<jk>new</jk> Logo(<js>"http://example.org/logo.png"</js>)); 315 * </p> 316 * 317 * @param value 318 * The new value for this property. 319 * <br>Can be <jk>null</jk> to unset the property. 320 * @return This object. 321 */ 322 public Feed setLogo(Logo value) { 323 logo = value; 324 return this; 325 } 326 327 /** 328 * Bean property fluent setter: <property>subtitle</property>. 329 * 330 * <p> 331 * Sets a human-readable description or subtitle for the feed as plain text. 332 * 333 * @param value 334 * The new value for this property. 335 * <br>Can be <jk>null</jk> to unset the property. 336 * @return This object. 337 */ 338 public Feed setSubtitle(String value) { 339 setSubtitle(new Text(value)); 340 return this; 341 } 342 343 /** 344 * Bean property setter: <property>subtitle</property>. 345 * 346 * <p> 347 * Sets a human-readable description or subtitle for the feed. 348 * 349 * <h5 class='section'>Example:</h5> 350 * <p class='bjava'> 351 * Feed <jv>feed</jv> = <jk>new</jk> Feed(...) 352 * .setSubtitle( 353 * <jk>new</jk> Text(<js>"html"</js>) 354 * .setText(<js>"A <em>comprehensive</em> guide to Atom feeds"</js>) 355 * ); 356 * </p> 357 * 358 * @param value 359 * The new value for this property. 360 * <br>Can be <jk>null</jk> to unset the property. 361 * @return This object. 362 */ 363 public Feed setSubtitle(Text value) { 364 subtitle = value; 365 return this; 366 } 367}