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.http.part;
018
019import static java.time.format.DateTimeFormatter.*;
020import static java.time.temporal.ChronoUnit.*;
021
022import java.time.*;
023import java.time.format.*;
024import java.util.*;
025import java.util.function.*;
026
027import org.apache.http.*;
028import org.apache.juneau.assertions.*;
029import org.apache.juneau.common.utils.*;
030
031/**
032 * A {@link NameValuePair} that consist of a single HTTP-date.
033 *
034 * <h5 class='section'>See Also:</h5><ul>
035 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</a>
036 * </ul>
037 */
038public class BasicDatePart extends BasicPart {
039
040   //-----------------------------------------------------------------------------------------------------------------
041   // Static
042   //-----------------------------------------------------------------------------------------------------------------
043
044   /**
045    * Static creator.
046    *
047    * @param name The part name.
048    * @param value The part value.
049    * @return A new {@link BasicDatePart} object, or <jk>null</jk> if the name or value is <jk>null</jk>.
050    */
051   public static BasicDatePart of(String name, ZonedDateTime value) {
052      if (Utils.isEmpty(name) || value == null)
053         return null;
054      return new BasicDatePart(name, value);
055   }
056
057   /**
058    * Static creator with delayed value.
059    *
060    * <p>
061    * Part value is re-evaluated on each call to {@link NameValuePair#getValue()}.
062    *
063    * @param name The part name.
064    * @param value The part value supplier.
065    * @return A new {@link BasicDatePart} object, or <jk>null</jk> if the name or supplier is <jk>null</jk>.
066    */
067   public static BasicDatePart of(String name, Supplier<ZonedDateTime> value) {
068      if (Utils.isEmpty(name) || value == null)
069         return null;
070      return new BasicDatePart(name, value);
071   }
072
073   //-----------------------------------------------------------------------------------------------------------------
074   // Instance
075   //-----------------------------------------------------------------------------------------------------------------
076
077   private final ZonedDateTime value;
078   private final Supplier<ZonedDateTime> supplier;
079
080   /**
081    * Constructor.
082    *
083    * @param name The part name.  Must not be <jk>null</jk>.
084    * @param value The part value.  Can be <jk>null</jk>.
085    */
086   public BasicDatePart(String name, ZonedDateTime value) {
087      super(name, value);
088      this.value = value;
089      this.supplier = null;
090   }
091
092   /**
093    * Constructor.
094    *
095    * @param name The part name.  Must not be <jk>null</jk>.
096    * @param value The part value supplier.  Can be <jk>null</jk> or supply <jk>null</jk>.
097    */
098   public BasicDatePart(String name, Supplier<ZonedDateTime> value) {
099      super(name, value);
100      this.value = null;
101      this.supplier = value;
102   }
103
104   /**
105    * Constructor.
106    *
107    * <p>
108    * <jk>null</jk> and empty values are treated as <jk>null</jk>.
109    * Otherwise parses using {@link DateTimeFormatter#ISO_DATE_TIME}.
110    *
111    * @param name The part name.  Must not be <jk>null</jk>.
112    * @param value The part value.  Can be <jk>null</jk>.
113    */
114   public BasicDatePart(String name, String value) {
115      super(name, value);
116      this.value = Utils.isEmpty(value) ? null : ZonedDateTime.from(ISO_DATE_TIME.parse(value)).truncatedTo(SECONDS);
117      this.supplier = null;
118   }
119
120   @Override /* Header */
121   public String getValue() {
122      ZonedDateTime v = value();
123      return v == null ? null : ISO_DATE_TIME.format(v);
124   }
125
126   /**
127    * Returns The part value as a {@link ZonedDateTime} wrapped in an {@link Optional}.
128    *
129    * @return The part value as a {@link ZonedDateTime} wrapped in an {@link Optional}.  Never <jk>null</jk>.
130    */
131   public Optional<ZonedDateTime> asZonedDateTime() {
132      return Utils.opt(toZonedDateTime());
133   }
134
135   /**
136    * Returns The part value as a {@link ZonedDateTime}.
137    *
138    * @return The part value as a {@link ZonedDateTime}, or <jk>null</jk> if the value <jk>null</jk>.
139    */
140   public ZonedDateTime toZonedDateTime() {
141      return value();
142   }
143
144   /**
145    * Provides the ability to perform fluent-style assertions on this part.
146    *
147    * @return A new fluent assertion object.
148    * @throws AssertionError If assertion failed.
149    */
150   public FluentZonedDateTimeAssertion<BasicDatePart> assertZonedDateTime() {
151      return new FluentZonedDateTimeAssertion<>(value(), this);
152   }
153
154   /**
155    * Return the value if present, otherwise return <c>other</c>.
156    *
157    * <p>
158    * This is a shortened form for calling <c>asZonedDateTime().orElse(<jv>other</jv>)</c>.
159    *
160    * @param other The value to be returned if there is no value present, can be <jk>null</jk>.
161    * @return The value, if present, otherwise <c>other</c>.
162    */
163   public ZonedDateTime orElse(ZonedDateTime other) {
164      ZonedDateTime x = value();
165      return x != null ? x : other;
166   }
167
168   private ZonedDateTime value() {
169      if (supplier != null)
170         return supplier.get();
171      return value;
172   }
173}