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 * & atomCategory* 045 * & atomContributor* 046 * & atomGenerator? 047 * & atomIcon? 048 * & atomId 049 * & atomLink* 050 * & atomLogo? 051 * & atomRights? 052 * & atomSubtitle? 053 * & atomTitle 054 * & atomUpdated 055 * & 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 private Generator generator; // atomGenerator? 116 private Icon icon; // atomIcon? 117 private Logo logo; // atomLogo? 118 private Text subtitle; // atomSubtitle? 119 private Entry[] entries; // atomEntry* 120 121 /** 122 * Normal constructor. 123 * 124 * @param id The feed identifier. 125 * @param title The feed title. 126 * @param updated The feed updated timestamp. 127 */ 128 public Feed(Id id, Text title, Calendar updated) { 129 super(id, title, updated); 130 } 131 132 /** 133 * Normal constructor. 134 * 135 * @param id The feed identifier. 136 * @param title The feed title. 137 * @param updated The feed updated timestamp. 138 */ 139 public Feed(String id, String title, String updated) { 140 super(id, title, updated); 141 } 142 143 /** Bean constructor. */ 144 public Feed() {} 145 146 147 //----------------------------------------------------------------------------------------------------------------- 148 // Bean properties 149 //----------------------------------------------------------------------------------------------------------------- 150 151 /** 152 * Bean property getter: <property>generator</property>. 153 * 154 * <p> 155 * Identifies the software agent used to generate the feed. 156 * 157 * <p> 158 * This is useful for debugging and analytics purposes, allowing consumers to identify the 159 * software responsible for producing the feed. 160 * 161 * @return The property value, or <jk>null</jk> if it is not set. 162 */ 163 public Generator getGenerator() { 164 return generator; 165 } 166 167 /** 168 * Bean property setter: <property>generator</property>. 169 * 170 * <p> 171 * Identifies the software agent used to generate the feed. 172 * 173 * <h5 class='section'>Example:</h5> 174 * <p class='bjava'> 175 * Feed <jv>feed</jv> = <jk>new</jk> Feed(...) 176 * .setGenerator( 177 * <jk>new</jk> Generator(<js>"My Blog Software"</js>) 178 * .setUri(<js>"http://www.example.com/software"</js>) 179 * .setVersion(<js>"2.0"</js>) 180 * ); 181 * </p> 182 * 183 * @param value 184 * The new value for this property. 185 * <br>Can be <jk>null</jk> to unset the property. 186 * @return This object. 187 */ 188 public Feed setGenerator(Generator value) { 189 this.generator = value; 190 return this; 191 } 192 193 /** 194 * Bean property getter: <property>icon</property>. 195 * 196 * <p> 197 * Identifies a small image that provides iconic visual identification for the feed. 198 * 199 * <p> 200 * Icons should be square and small (typically 16x16 or similar). The image should have an 201 * aspect ratio of 1 (horizontal) to 1 (vertical). 202 * 203 * @return The property value, or <jk>null</jk> if it is not set. 204 */ 205 public Icon getIcon() { 206 return icon; 207 } 208 209 /** 210 * Bean property setter: <property>icon</property>. 211 * 212 * <p> 213 * Identifies a small image that provides iconic visual identification for the feed. 214 * 215 * <h5 class='section'>Example:</h5> 216 * <p class='bjava'> 217 * Feed <jv>feed</jv> = <jk>new</jk> Feed(...) 218 * .setIcon(<jk>new</jk> Icon(<js>"http://example.org/icon.png"</js>)); 219 * </p> 220 * 221 * @param value 222 * The new value for this property. 223 * <br>Can be <jk>null</jk> to unset the property. 224 * @return This object. 225 */ 226 public Feed setIcon(Icon value) { 227 this.icon = value; 228 return this; 229 } 230 231 /** 232 * Bean property getter: <property>logo</property>. 233 * 234 * <p> 235 * Identifies a larger image that provides visual identification for the feed. 236 * 237 * <p> 238 * Logos should be twice as wide as they are tall (aspect ratio of 2:1). 239 * 240 * @return The property value, or <jk>null</jk> if it is not set. 241 */ 242 public Logo getLogo() { 243 return logo; 244 } 245 246 /** 247 * Bean property setter: <property>logo</property>. 248 * 249 * <p> 250 * Identifies a larger image that provides visual identification for the feed. 251 * 252 * <h5 class='section'>Example:</h5> 253 * <p class='bjava'> 254 * Feed <jv>feed</jv> = <jk>new</jk> Feed(...) 255 * .setLogo(<jk>new</jk> Logo(<js>"http://example.org/logo.png"</js>)); 256 * </p> 257 * 258 * @param value 259 * The new value for this property. 260 * <br>Can be <jk>null</jk> to unset the property. 261 * @return This object. 262 */ 263 public Feed setLogo(Logo value) { 264 this.logo = value; 265 return this; 266 } 267 268 /** 269 * Bean property getter: <property>subtitle</property>. 270 * 271 * <p> 272 * Returns a human-readable description or subtitle for the feed. 273 * 274 * <p> 275 * The subtitle provides additional context about the feed's purpose or content beyond 276 * what is conveyed in the title. 277 * 278 * @return The property value, or <jk>null</jk> if it is not set. 279 */ 280 public Text getSubtitle() { 281 return subtitle; 282 } 283 284 /** 285 * Bean property setter: <property>subtitle</property>. 286 * 287 * <p> 288 * Sets a human-readable description or subtitle for the feed. 289 * 290 * <h5 class='section'>Example:</h5> 291 * <p class='bjava'> 292 * Feed <jv>feed</jv> = <jk>new</jk> Feed(...) 293 * .setSubtitle( 294 * <jk>new</jk> Text(<js>"html"</js>) 295 * .setText(<js>"A <em>comprehensive</em> guide to Atom feeds"</js>) 296 * ); 297 * </p> 298 * 299 * @param value 300 * The new value for this property. 301 * <br>Can be <jk>null</jk> to unset the property. 302 * @return This object. 303 */ 304 public Feed setSubtitle(Text value) { 305 this.subtitle = value; 306 return this; 307 } 308 309 /** 310 * Bean property fluent setter: <property>subtitle</property>. 311 * 312 * <p> 313 * Sets a human-readable description or subtitle for the feed as plain text. 314 * 315 * @param value 316 * The new value for this property. 317 * <br>Can be <jk>null</jk> to unset the property. 318 * @return This object. 319 */ 320 public Feed setSubtitle(String value) { 321 setSubtitle(new Text(value)); 322 return this; 323 } 324 325 /** 326 * Bean property getter: <property>entries</property>. 327 * 328 * <p> 329 * Returns the individual entries contained within this feed. 330 * 331 * <p> 332 * Each entry represents a single item in the feed, such as a blog post, news article, 333 * podcast episode, or other discrete piece of content. Entries contain their own metadata 334 * including title, content, links, and timestamps. 335 * 336 * @return The property value, or <jk>null</jk> if it is not set. 337 */ 338 @Xml(format=COLLAPSED) 339 public Entry[] getEntries() { 340 return entries; 341 } 342 343 /** 344 * Bean property setter: <property>entries</property>. 345 * 346 * <p> 347 * Sets the individual entries contained within this feed. 348 * 349 * <h5 class='section'>Example:</h5> 350 * <p class='bjava'> 351 * Feed <jv>feed</jv> = <jk>new</jk> Feed(...) 352 * .setEntries( 353 * <jk>new</jk> Entry( 354 * <js>"tag:example.org,2024:entry1"</js>, 355 * <js>"First Post"</js>, 356 * <js>"2024-01-15T12:00:00Z"</js> 357 * ) 358 * .setContent( 359 * <jk>new</jk> Content(<js>"html"</js>) 360 * .setText(<js>"<p>This is the content</p>"</js>) 361 * ), 362 * <jk>new</jk> Entry( 363 * <js>"tag:example.org,2024:entry2"</js>, 364 * <js>"Second Post"</js>, 365 * <js>"2024-01-16T12:00:00Z"</js> 366 * ) 367 * ); 368 * </p> 369 * 370 * @param value 371 * The new value for this property. 372 * <br>Can be <jk>null</jk> to unset the property. 373 * @return This object. 374 */ 375 public Feed setEntries(Entry...value) { 376 this.entries = value; 377 return this; 378 } 379 380 //----------------------------------------------------------------------------------------------------------------- 381 // Overridden setters (to simplify method chaining) 382 //----------------------------------------------------------------------------------------------------------------- 383 384 @Override /* Overridden from Common */ 385 public Feed setBase(Object value) { 386 super.setBase(value); 387 return this; 388 } 389 390 @Override /* Overridden from Common */ 391 public Feed setLang(String value) { 392 super.setLang(value); 393 return this; 394 } 395 396 @Override /* Overridden from CommonEntry */ 397 public Feed setAuthors(Person...value) { 398 super.setAuthors(value); 399 return this; 400 } 401 402 @Override /* Overridden from CommonEntry */ 403 public Feed setCategories(Category...value) { 404 super.setCategories(value); 405 return this; 406 } 407 408 @Override /* Overridden from CommonEntry */ 409 public Feed setContributors(Person...value) { 410 super.setContributors(value); 411 return this; 412 } 413 414 @Override /* Overridden from CommonEntry */ 415 public Feed setId(String value) { 416 super.setId(value); 417 return this; 418 } 419 420 @Override /* Overridden from CommonEntry */ 421 public Feed setId(Id value) { 422 super.setId(value); 423 return this; 424 } 425 426 @Override /* Overridden from CommonEntry */ 427 public Feed setLinks(Link...value) { 428 super.setLinks(value); 429 return this; 430 } 431 432 @Override /* Overridden from CommonEntry */ 433 public Feed setRights(String value) { 434 super.setRights(value); 435 return this; 436 } 437 438 @Override /* Overridden from CommonEntry */ 439 public Feed setRights(Text value) { 440 super.setRights(value); 441 return this; 442 } 443 444 @Override /* Overridden from CommonEntry */ 445 public Feed setTitle(String value) { 446 super.setTitle(value); 447 return this; 448 } 449 450 @Override /* Overridden from CommonEntry */ 451 public Feed setTitle(Text value) { 452 super.setTitle(value); 453 return this; 454 } 455 456 @Override /* Overridden from CommonEntry */ 457 public Feed setUpdated(String value) { 458 super.setUpdated(value); 459 return this; 460 } 461 462 @Override /* Overridden from CommonEntry */ 463 public Feed setUpdated(Calendar value) { 464 super.setUpdated(value); 465 return this; 466 } 467}