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.CopyUtils.*;
020import static org.apache.juneau.commons.utils.Shorts.*;
021import static org.apache.juneau.commons.utils.StringUtils.*;
022import static org.apache.juneau.marshall.xml.XmlFormat.*;
023
024import java.util.*;
025
026import org.apache.juneau.commons.time.*;
027import org.apache.juneau.marshall.xml.*;
028
029/**
030 * Base class for feed-level and entry-level Atom elements.
031 *
032 * <p>
033 * This abstract class contains properties common to {@link Feed}, {@link Entry}, and {@link Source}
034 * elements. These elements share a common set of metadata properties including authors, contributors,
035 * categories, links, and timestamps.
036 *
037 * <p>
038 * Common properties include:
039 * <ul class='spaced-list'>
040 *    <li><b>id</b> (required) - Permanent, unique identifier
041 *    <li><b>title</b> (required) - Human-readable title
042 *    <li><b>updated</b> (required) - Last modification timestamp
043 *    <li><b>authors</b> - Author information
044 *    <li><b>categories</b> - Classification/tagging information
045 *    <li><b>contributors</b> - Contributor information
046 *    <li><b>links</b> - Related resources
047 *    <li><b>rights</b> - Copyright/rights information
048 * </ul>
049 *
050 * <p>
051 * This class extends {@link Common}, inheriting the <c>xml:base</c> and <c>xml:lang</c> attributes.
052 *
053 * <h5 class='section'>See Also:</h5><ul>
054 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanAtom">juneau-bean-atom</a>
055 *    <li class='extlink'><a class="doclink" href="https://tools.ietf.org/html/rfc4287">RFC 4287 - The Atom Syndication Format</a>
056 * </ul>
057 *
058 * @param <SELF> The self type for fluent setters.
059 */
060@SuppressWarnings({
061   "java:S119" // 'SELF' (CRTP self-type) is intentional and clearer than a single-letter name.
062})
063public class CommonEntry<SELF extends CommonEntry<SELF>> extends Common {
064
065   private Person[] authors;
066   private Category[] categories;
067   private Person[] contributors;
068   private Id id;
069   private Link[] links;
070   private Text rights;
071   private Text title;
072   private Calendar updated;
073
074   /** Bean constructor. */
075   public CommonEntry() {}
076
077   @SuppressWarnings({
078      "unchecked" // CRTP self cast: SELF is bound to the concrete subclass, so (SELF) this is always valid
079   })
080   private SELF self() {
081      return (SELF) this;
082   }
083
084   /**
085    * Normal constructor.
086    *
087    * @param id The ID of this object.  Can be <jk>null</jk> to leave the property unset.
088    * @param title The title of this object.  Can be <jk>null</jk> to leave the property unset.
089    * @param updated The updated timestamp of this object.  Can be <jk>null</jk> to leave the property unset.
090    */
091   public CommonEntry(Id id, Text title, Calendar updated) {
092      setId(id).setTitle(title).setUpdated(updated);
093   }
094
095   /**
096    * Normal constructor.
097    *
098    * @param id The ID of this object.  Can be <jk>null</jk>, in which case the property is set to an {@link Id} with no text (not left unset).
099    * @param title The title of this object.  Can be <jk>null</jk>, in which case the property is set to a {@link Text} with no text (not left unset).
100    * @param updated The updated timestamp of this object.  Can be <jk>null</jk> or blank to leave the property unset.
101    */
102   public CommonEntry(String id, String title, String updated) {
103      setId(id).setTitle(title).setUpdated(updated);
104   }
105
106   /**
107    * Bean property getter:  <property>authors</property>.
108    *
109    * <p>
110    * The list of authors for this object.
111    *
112    * @return The property value, or <jk>null</jk> if it is not set.
113    */
114   @Xml(format = COLLAPSED, childName = "author")
115   public Person[] getAuthors() { return cp(authors); }
116
117   /**
118    * Bean property getter:  <property>categories</property>.
119    *
120    * <p>
121    * The list of categories of this object.
122    *
123    * @return The property value, or <jk>null</jk> if it is not set.
124    */
125   @Xml(format = COLLAPSED, childName = "category")
126   public Category[] getCategories() { return cp(categories); }
127
128   /**
129    * Bean property getter:  <property>contributors</property>.
130    *
131    * <p>
132    * The list of contributors of this object.
133    *
134    * @return The property value, or <jk>null</jk> if it is not set.
135    */
136   @Xml(format = COLLAPSED, childName = "contributor")
137   public Person[] getContributors() { return cp(contributors); }
138
139   /**
140    * Bean property getter:  <property>id</property>.
141    *
142    * <p>
143    * The ID of this object.
144    *
145    * @return The property value, or <jk>null</jk> if it is not set.
146    */
147   public Id getId() { return id; }
148
149   /**
150    * Bean property getter:  <property>links</property>.
151    *
152    * <p>
153    * The list of links of this object.
154    *
155    * @return The property value, or <jk>null</jk> if it is not set.
156    */
157   @Xml(format = COLLAPSED)
158   public Link[] getLinks() { return cp(links); }
159
160   /**
161    * Bean property getter:  <property>rights</property>.
162    *
163    * <p>
164    * The rights statement of this object.
165    *
166    * @return The property value, or <jk>null</jk> if it is not set.
167    */
168   public Text getRights() { return rights; }
169
170   /**
171    * Bean property getter:  <property>title</property>.
172    *
173    * <p>
174    * The title of this object.
175    *
176    * @return The property value, or <jk>null</jk> if it is not set.
177    */
178   public Text getTitle() { return title; }
179
180   /**
181    * Bean property getter:  <property>updated</property>.
182    *
183    * <p>
184    * The update timestamp of this object.
185    *
186    * @return The property value, or <jk>null</jk> if it is not set.
187    */
188   public Calendar getUpdated() { return cloneOf(updated); }
189
190   /**
191    * Bean property setter:  <property>authors</property>.
192    *
193    * <p>
194    * The list of authors for this object.
195    *
196    * @param value
197    *    The new value for this property.
198    *    <br>Can be <jk>null</jk> to unset the property.
199    * @return This object
200    */
201   public SELF setAuthors(Person...value) {
202      authors = cp(value);
203      return self();
204   }
205
206   @Override /* Overridden from Common */
207   public SELF setBase(Object value) {
208      super.setBase(value);
209      return self();
210   }
211
212   /**
213    * Bean property setter:  <property>categories</property>.
214    *
215    * <p>
216    * The list of categories of this object.
217    *
218    * @param value
219    *    The new value for this property.
220    *    <br>Can be <jk>null</jk> to unset the property.
221    * @return This object
222    */
223   public SELF setCategories(Category...value) {
224      categories = cp(value);
225      return self();
226   }
227
228   /**
229    * Bean property setter:  <property>contributors</property>.
230    *
231    * <p>
232    * The list of contributors of this object.
233    *
234    * @param value
235    *    The new value for this property.
236    *    <br>Can be <jk>null</jk> to unset the property.
237    * @return This object
238    */
239   public SELF setContributors(Person...value) {
240      contributors = cp(value);
241      return self();
242   }
243
244   /**
245    * Bean property setter:  <property>id</property>.
246    *
247    * <p>
248    * The ID of this object.
249    *
250    * @param value
251    *    The new value for this property.
252    *    <br>Can be <jk>null</jk> to unset the property.
253    * @return This object
254    */
255   public SELF setId(Id value) {
256      id = value;
257      return self();
258   }
259
260   /**
261    * Bean property fluent setter:  <property>id</property>.
262    *
263    * <p>
264    * The ID of this object.
265    *
266    * @param value
267    *    The new value for this property.
268    *    <br>Can be <jk>null</jk> to unset the property.
269    * @return This object.
270    */
271   public SELF setId(String value) {
272      setId(new Id(value));
273      return self();
274   }
275
276   @Override /* Overridden from Common */
277   public SELF setLang(String value) {
278      super.setLang(value);
279      return self();
280   }
281
282   /**
283    * Bean property setter:  <property>links</property>.
284    *
285    * <p>
286    * The list of links of this object.
287    *
288    * @param value
289    *    The new value for this property.
290    *    <br>Can be <jk>null</jk> to unset the property.
291    * @return This object
292    */
293   public SELF setLinks(Link...value) {
294      links = cp(value);
295      return self();
296   }
297
298   /**
299    * Bean property fluent setter:  <property>rights</property>.
300    *
301    * <p>
302    * The rights statement of this object.
303    *
304    * @param value
305    *    The new value for this property.
306    *    <br>Can be <jk>null</jk> to unset the property.
307    * @return This object.
308    */
309   public SELF setRights(String value) {
310      setRights(new Text().setText(value));
311      return self();
312   }
313
314   /**
315    * Bean property setter:  <property>rights</property>.
316    *
317    * <p>
318    * The rights statement of this object.
319    *
320    * @param value
321    *    The new value for this property.
322    *    <br>Can be <jk>null</jk> to unset the property.
323    * @return This object
324    */
325   public SELF setRights(Text value) {
326      rights = value;
327      return self();
328   }
329
330   /**
331    * Bean property fluent setter:  <property>title</property>.
332    *
333    * <p>
334    * The title of this object.
335    *
336    * @param value
337    *    The new value for this property.
338    *    <br>Can be <jk>null</jk> to unset the property.
339    * @return This object.
340    */
341   public SELF setTitle(String value) {
342      setTitle(new Text().setText(value));
343      return self();
344   }
345
346   /**
347    * Bean property setter:  <property>title</property>.
348    *
349    * <p>
350    * The title of this object.
351    *
352    * @param value
353    *    The new value for this property.
354    *    <br>Can be <jk>null</jk> to unset the property.
355    * @return This object
356    */
357   public SELF setTitle(Text value) {
358      title = value;
359      return self();
360   }
361
362   /**
363    * Bean property setter:  <property>updated</property>.
364    *
365    * <p>
366    * The update timestamp of this object.
367    *
368    * @param value
369    *    The new value for this property.
370    *    <br>Can be <jk>null</jk> to unset the property.
371    * @return This object
372    */
373   public SELF setUpdated(Calendar value) {
374      updated = cloneOf(value);
375      return self();
376   }
377
378   /**
379    * Bean property fluent setter:  <property>updated</property>.
380    *
381    * <p>
382    * The update timestamp of this object.
383    *
384    * @param value
385    *    The new value for this property.
386    *    <br>Can be <jk>null</jk> to unset the property.
387    * @return This object.
388    */
389   public SELF setUpdated(String value) {
390      setUpdated(o(value).filter(x1 -> ! isBlank(x1)).map(x -> GranularZonedDateTime.of(value).getZonedDateTime()).map(GregorianCalendar::from).orElse(null));
391      return self();
392   }
393}