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