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.StringUtils.*; 020import static org.apache.juneau.commons.utils.Utils.*; 021 022import java.util.*; 023 024import org.apache.juneau.annotation.*; 025import org.apache.juneau.commons.time.*; 026 027/** 028 * Represents an individual entry within an Atom feed or as a standalone Atom document. 029 * 030 * <p> 031 * An Atom entry is a discrete item of content within a feed, such as a blog post, news article, 032 * podcast episode, or other individual piece of content. Entries can exist within a feed or be 033 * published as standalone Atom documents. 034 * 035 * <p> 036 * Each entry contains metadata about the content (title, authors, timestamps) and optionally the 037 * content itself or links to it. Entries are designed to be independently meaningful and may be 038 * consumed separately from their containing feed. 039 * 040 * <h5 class='figure'>Schema</h5> 041 * <p class='bschema'> 042 * atomEntry = 043 * element atom:entry { 044 * atomCommonAttributes, 045 * (atomAuthor* 046 * & atomCategory* 047 * & atomContent? 048 * & atomContributor* 049 * & atomId 050 * & atomLink* 051 * & atomPublished? 052 * & atomRights? 053 * & atomSource? 054 * & atomSummary? 055 * & atomTitle 056 * & atomUpdated 057 * & extensionElement*) 058 * } 059 * </p> 060 * 061 * <h5 class='section'>Required Elements:</h5> 062 * <p> 063 * Per RFC 4287, the following elements are required in an entry: 064 * <ul class='spaced-list'> 065 * <li><c>atom:id</c> - A permanent, universally unique identifier for the entry. 066 * <li><c>atom:title</c> - A human-readable title for the entry. 067 * <li><c>atom:updated</c> - The most recent instant in time when the entry was modified. 068 * </ul> 069 * 070 * <h5 class='section'>Recommended Elements:</h5> 071 * <p> 072 * The following elements are recommended: 073 * <ul class='spaced-list'> 074 * <li><c>atom:author</c> - Authors of the entry (required if feed doesn't have authors). 075 * <li><c>atom:content</c> or <c>atom:link[@rel="alternate"]</c> - Either content or alternate link. 076 * <li><c>atom:summary</c> - Brief summary of the entry (required if content is not inline). 077 * </ul> 078 * 079 * <h5 class='section'>Example:</h5> 080 * <p class='bjava'> 081 * <jc>// Create an entry</jc> 082 * Entry <jv>entry</jv> = <jk>new</jk> Entry( 083 * <js>"tag:example.org,2024:entry1"</js>, 084 * <js>"My First Blog Post"</js>, 085 * <js>"2024-01-15T12:00:00Z"</js> 086 * ) 087 * .setAuthors( 088 * <jk>new</jk> Person(<js>"Jane Doe"</js>) 089 * .setEmail(<js>"jane@example.org"</js>) 090 * ) 091 * .setContent( 092 * <jk>new</jk> Content(<js>"html"</js>) 093 * .setText(<js>"<p>This is my first blog post!</p>"</js>) 094 * ) 095 * .setSummary(<js>"An introduction to my new blog"</js>) 096 * .setPublished(<js>"2024-01-15T10:00:00Z"</js>) 097 * .setLinks( 098 * <jk>new</jk> Link(<js>"alternate"</js>, <js>"text/html"</js>, <js>"http://example.org/posts/1"</js>) 099 * ); 100 * </p> 101 * 102 * <h5 class='section'>Specification:</h5> 103 * <p> 104 * Represents an <c>atomEntry</c> construct in the 105 * <a class="doclink" href="https://tools.ietf.org/html/rfc4287#section-4.1.2">RFC 4287 - Section 4.1.2</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 = "entry") 113public class Entry extends CommonEntry { 114 115 private Content content; 116 private Calendar published; 117 private Source source; 118 private Text summary; 119 120 /** Bean constructor. */ 121 public Entry() {} 122 123 /** 124 * Normal constructor. 125 * 126 * @param id The ID of this entry. 127 * @param title The title of this entry. 128 * @param updated The updated timestamp of this entry. 129 */ 130 public Entry(Id id, Text title, Calendar updated) { 131 super(id, title, updated); 132 } 133 134 /** 135 * Normal constructor. 136 * 137 * @param id The ID of this entry. 138 * @param title The title of this entry. 139 * @param updated The updated timestamp of this entry. 140 */ 141 public Entry(String id, String title, String updated) { 142 super(id, title, updated); 143 } 144 145 /** 146 * Bean property getter: <property>content</property>. 147 * 148 * <p> 149 * Returns the content of this entry, or a link to it. 150 * 151 * <p> 152 * The content element contains or links to the complete content of the entry. It can contain 153 * text, HTML, XHTML, or other media types. When not present, the entry must have an alternate 154 * link pointing to the content. 155 * 156 * @return The property value, or <jk>null</jk> if it is not set. 157 */ 158 public Content getContent() { return content; } 159 160 /** 161 * Bean property getter: <property>published</property>. 162 * 163 * <p> 164 * Returns the time when this entry was first published or made available. 165 * 166 * <p> 167 * This differs from the updated time in that it represents the original publication date, 168 * which typically doesn't change even when the entry is modified. The updated timestamp 169 * reflects the last modification time. 170 * 171 * @return The property value, or <jk>null</jk> if it is not set. 172 */ 173 public Calendar getPublished() { return published; } 174 175 /** 176 * Bean property getter: <property>source</property>. 177 * 178 * <p> 179 * Returns metadata about the source feed if this entry was copied from another feed. 180 * 181 * <p> 182 * When an entry is copied or aggregated from another feed, the source element preserves 183 * metadata from the original feed. This is useful for attribution and tracking the origin 184 * of syndicated content. 185 * 186 * @return The property value, or <jk>null</jk> if it is not set. 187 */ 188 public Source getSource() { return source; } 189 190 /** 191 * Bean property getter: <property>summary</property>. 192 * 193 * <p> 194 * Returns a short summary, abstract, or excerpt of the entry. 195 * 196 * <p> 197 * The summary is typically used in feed readers to give users a preview of the entry's 198 * content without loading the full content. It's especially useful when content is not 199 * inline or is very long. 200 * 201 * @return The property value, or <jk>null</jk> if it is not set. 202 */ 203 public Text getSummary() { return summary; } 204 205 @Override /* Overridden from CommonEntry */ 206 public Entry setAuthors(Person...value) { 207 super.setAuthors(value); 208 return this; 209 } 210 211 @Override /* Overridden from Common */ 212 public Entry setBase(Object value) { 213 super.setBase(value); 214 return this; 215 } 216 217 @Override /* Overridden from CommonEntry */ 218 public Entry setCategories(Category...value) { 219 super.setCategories(value); 220 return this; 221 } 222 223 /** 224 * Bean property setter: <property>content</property>. 225 * 226 * <p> 227 * Sets the content of this entry. 228 * 229 * <h5 class='section'>Examples:</h5> 230 * <p class='bjava'> 231 * <jc>// Plain text content</jc> 232 * Entry <jv>entry</jv> = <jk>new</jk> Entry(...) 233 * .setContent( 234 * <jk>new</jk> Content(<js>"text"</js>) 235 * .setText(<js>"This is plain text content"</js>) 236 * ); 237 * 238 * <jc>// HTML content</jc> 239 * Entry <jv>entry2</jv> = <jk>new</jk> Entry(...) 240 * .setContent( 241 * <jk>new</jk> Content(<js>"html"</js>) 242 * .setText(<js>"<p>This is <strong>HTML</strong> content</p>"</js>) 243 * ); 244 * 245 * <jc>// Link to external content</jc> 246 * Entry <jv>entry3</jv> = <jk>new</jk> Entry(...) 247 * .setContent( 248 * <jk>new</jk> Content() 249 * .setType(<js>"video/mp4"</js>) 250 * .setSrc(<js>"http://example.org/video.mp4"</js>) 251 * ); 252 * </p> 253 * 254 * @param value 255 * The new value for this property. 256 * <br>Can be <jk>null</jk> to unset the property. 257 * @return This object. 258 */ 259 public Entry setContent(Content value) { 260 content = value; 261 return this; 262 } 263 264 @Override /* Overridden from CommonEntry */ 265 public Entry setContributors(Person...value) { 266 super.setContributors(value); 267 return this; 268 } 269 270 @Override /* Overridden from CommonEntry */ 271 public Entry setId(Id value) { 272 super.setId(value); 273 return this; 274 } 275 276 @Override /* Overridden from CommonEntry */ 277 public Entry setId(String value) { 278 super.setId(value); 279 return this; 280 } 281 282 @Override /* Overridden from Common */ 283 public Entry setLang(String value) { 284 super.setLang(value); 285 return this; 286 } 287 288 @Override /* Overridden from CommonEntry */ 289 public Entry setLinks(Link...value) { 290 super.setLinks(value); 291 return this; 292 } 293 294 /** 295 * Bean property setter: <property>published</property>. 296 * 297 * <p> 298 * Sets the time when this entry was first published or made available. 299 * 300 * <h5 class='section'>Example:</h5> 301 * <p class='bjava'> 302 * Entry <jv>entry</jv> = <jk>new</jk> Entry(...) 303 * .setPublished(Calendar.<jsm>getInstance</jsm>()); 304 * </p> 305 * 306 * @param value 307 * The new value for this property. 308 * <br>Can be <jk>null</jk> to unset the property. 309 * @return This object. 310 */ 311 public Entry setPublished(Calendar value) { 312 published = value; 313 return this; 314 } 315 316 /** 317 * Bean property fluent setter: <property>published</property>. 318 * 319 * <p> 320 * Sets the time when this entry was first published using an ISO-8601 date string. 321 * 322 * <h5 class='section'>Example:</h5> 323 * <p class='bjava'> 324 * Entry <jv>entry</jv> = <jk>new</jk> Entry(...) 325 * .setPublished(<js>"2024-01-15T10:00:00Z"</js>); 326 * </p> 327 * 328 * @param value 329 * The new value for this property in ISO-8601 format. 330 * <br>Can be <jk>null</jk> to unset the property. 331 * @return This object. 332 */ 333 public Entry setPublished(String value) { 334 setPublished(opt(value).filter(x1 -> ! isBlank(x1)).map(x -> GranularZonedDateTime.of(value).getZonedDateTime()).map(GregorianCalendar::from).orElse(null)); 335 return this; 336 } 337 338 @Override /* Overridden from CommonEntry */ 339 public Entry setRights(String value) { 340 super.setRights(value); 341 return this; 342 } 343 344 @Override /* Overridden from CommonEntry */ 345 public Entry setRights(Text value) { 346 super.setRights(value); 347 return this; 348 } 349 350 /** 351 * Bean property setter: <property>source</property>. 352 * 353 * <p> 354 * Sets metadata about the source feed if this entry was copied from another feed. 355 * 356 * <h5 class='section'>Example:</h5> 357 * <p class='bjava'> 358 * Entry <jv>entry</jv> = <jk>new</jk> Entry(...) 359 * .setSource( 360 * <jk>new</jk> Source() 361 * .setId(<js>"tag:originalblog.example.com,2024:feed"</js>) 362 * .setTitle(<js>"Original Blog"</js>) 363 * .setUpdated(<js>"2024-01-15T12:00:00Z"</js>) 364 * ); 365 * </p> 366 * 367 * @param value 368 * The new value for this property. 369 * <br>Can be <jk>null</jk> to unset the property. 370 * @return This object. 371 */ 372 public Entry setSource(Source value) { 373 source = value; 374 return this; 375 } 376 377 /** 378 * Bean property fluent setter: <property>summary</property>. 379 * 380 * <p> 381 * Sets a short summary, abstract, or excerpt of the entry as plain text. 382 * 383 * @param value 384 * The new value for this property. 385 * <br>Can be <jk>null</jk> to unset the property. 386 * @return This object. 387 */ 388 public Entry setSummary(String value) { 389 setSummary(new Text(value)); 390 return this; 391 } 392 393 /** 394 * Bean property setter: <property>summary</property>. 395 * 396 * <p> 397 * Sets a short summary, abstract, or excerpt of the entry. 398 * 399 * <h5 class='section'>Example:</h5> 400 * <p class='bjava'> 401 * Entry <jv>entry</jv> = <jk>new</jk> Entry(...) 402 * .setSummary( 403 * <jk>new</jk> Text(<js>"text"</js>) 404 * .setText(<js>"This entry discusses the benefits of Atom feeds..."</js>) 405 * ); 406 * </p> 407 * 408 * @param value 409 * The new value for this property. 410 * <br>Can be <jk>null</jk> to unset the property. 411 * @return This object. 412 */ 413 public Entry setSummary(Text value) { 414 summary = value; 415 return this; 416 } 417 418 @Override /* Overridden from CommonEntry */ 419 public Entry setTitle(String value) { 420 super.setTitle(value); 421 return this; 422 } 423 424 @Override /* Overridden from CommonEntry */ 425 public Entry setTitle(Text value) { 426 super.setTitle(value); 427 return this; 428 } 429 430 @Override /* Overridden from CommonEntry */ 431 public Entry setUpdated(Calendar value) { 432 super.setUpdated(value); 433 return this; 434 } 435 436 @Override /* Overridden from CommonEntry */ 437 public Entry setUpdated(String value) { 438 super.setUpdated(value); 439 return this; 440 } 441}