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.microservice.jetty;
018
019import static org.apache.juneau.commons.utils.IoUtils.*;
020import static org.apache.juneau.commons.utils.Shorts.*;
021
022import java.io.*;
023import java.nio.file.*;
024import java.time.*;
025
026/**
027 * Programmatic settings for the Jetty server contributed by {@link JettyConfiguration}.
028 *
029 * <p>
030 * Users who need to override the defaults pulled from <c>Config</c> / <c>ManifestFile</c> should
031 * contribute a <c>@Bean JettySettings</c> from their own <c>@Configuration</c> class.  Any value
032 * left {@code null} on this settings bean falls back to the corresponding <c>Config</c> / <c>ManifestFile</c>
033 * entry, then to a hard-coded default.
034 *
035 * <h5 class='section'>Example:</h5>
036 * <p class='bjava'>
037 *    <ja>@Configuration</ja>
038 *    <jk>public class</jk> MyAppConfig {
039 *       <ja>@Bean</ja>
040 *       <jk>public</jk> JettySettings jettySettings() {
041 *          <jk>return</jk> JettySettings.<jsm>create</jsm>()
042 *             .ports(8080, 0)
043 *             .build();
044 *       }
045 *    }
046 * </p>
047 *
048 * <h5 class='section'>See Also:</h5><ul>
049 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauMicroserviceJetty">juneau-microservice-jetty</a>
050 * </ul>
051 *
052 * @since 10.0.0
053 */
054public class JettySettings {
055
056   /**
057    * Builder for {@link JettySettings}.
058    */
059   public static class Builder {
060
061      int[] ports;
062      String jettyXml;
063      Boolean jettyXmlResolveVars;
064      Duration stopTimeout;
065      Duration shutdownSettleDelay;
066
067      Builder() {}
068
069      /**
070       * Builds a new {@link JettySettings} from this builder.
071       *
072       * @return A new settings instance.
073       */
074      public JettySettings build() {
075         return new JettySettings(this);
076      }
077
078      /**
079       * Specifies the ports to try when binding the Jetty server.
080       *
081       * <p>
082       * The first available port is used.  A value of <c>0</c> indicates "try a random port".  When set, this
083       * value takes precedence over the <c>Jetty/port</c> config-file entry and the <c>Jetty-Port</c>
084       * manifest entry.
085       *
086       * @param value The candidate ports, in priority order.  Can be <jk>null</jk> to defer to config / manifest.
087       * @return This object.
088       */
089      public Builder ports(int...value) {
090         ports = cp(value);
091         return this;
092      }
093
094      /**
095       * Specifies the contents or location of the <c>jetty.xml</c> file used to build the Jetty server.
096       *
097       * <p>
098       * When set, this value takes precedence over the <c>Jetty/config</c> config-file entry and the
099       * <c>Jetty-Config</c> manifest entry.  When not set, the component falls back to those values and
100       * finally to a <c>jetty.xml</c> file located on the file system or classpath.
101       *
102       * @param value The contents or location of the file.  Can be any of:
103       *    <ul>
104       *       <li>{@link String} - Relative path to a file on the file system or classpath, or the raw XML content if it begins with <c>&lt;</c>.
105       *       <li>{@link File} - File on the file system.
106       *       <li>{@link Path} - Path on the file system.
107       *       <li>{@link InputStream} - Raw contents as a <c>UTF-8</c> encoded stream.
108       *       <li>{@link Reader} - Raw contents.
109       *    </ul>
110       *    <br>Can be <jk>null</jk> (defers to config / manifest / classpath resolution).
111       * @param resolveVars If <jk>true</jk>, SVL variables in the file will automatically be resolved.
112       * @return This object.
113       * @throws IOException Thrown by underlying stream.
114       */
115      public Builder jettyXml(Object value, boolean resolveVars) throws IOException {
116         if (value == null)
117            jettyXml = null;
118         else if (value instanceof String value2)
119            jettyXml = value2.startsWith("<") ? value2 : read(new File(value2));
120         else if (value instanceof File value2)
121            jettyXml = read(value2);
122         else if (value instanceof Path value2)
123            jettyXml = read(value2);
124         else if (value instanceof InputStream value2)
125            jettyXml = read(value2);
126         else if (value instanceof Reader value2)
127            jettyXml = read(value2);
128         else
129            throw rex("Invalid object type passed to jettyXml(Object): %s", cn(value));
130         jettyXmlResolveVars = resolveVars;
131         return this;
132      }
133
134      /**
135       * Specifies the bounded graceful-shutdown drain timeout for the Jetty server.
136       *
137       * <p>
138       * On stop, the server stops accepting new connections and waits up to this duration for in-flight requests
139       * to complete before the connector closes (Jetty's <c>stopTimeout</c>).  When set, this value takes
140       * precedence over the <c>Jetty/stopTimeout</c> config-file entry (in milliseconds).  When neither is set,
141       * a default of {@code 30s} is applied.
142       *
143       * @param value The drain timeout.  Can be <jk>null</jk> to defer to config, then to the default.
144       * @return This object.
145       */
146      public Builder stopTimeout(Duration value) {
147         stopTimeout = value;
148         return this;
149      }
150
151      /**
152       * Specifies the settle delay applied between flipping the readiness probe out of service and stopping the
153       * connector.
154       *
155       * <p>
156       * On stop, the readiness probe ({@code /readyz}) flips to {@code 503} <i>before</i> the connector closes so a
157       * load balancer / Kubernetes stops routing new traffic.  This brief delay gives the load balancer time to
158       * observe the {@code 503} before in-flight requests are drained.  When set, this value takes precedence over
159       * the <c>Jetty/shutdownSettleDelay</c> config-file entry (in milliseconds).  When neither is set, no settle
160       * delay is applied (defaults to {@code 0}) &mdash; the recommended Kubernetes pattern is a {@code preStop}
161       * hook sleep instead.
162       *
163       * @param value The settle delay.  Can be <jk>null</jk> to defer to config, then to the default.
164       * @return This object.
165       */
166      public Builder shutdownSettleDelay(Duration value) {
167         shutdownSettleDelay = value;
168         return this;
169      }
170   }
171
172   /**
173    * Creates a new builder for this object.
174    *
175    * @return A new builder.
176    */
177   public static Builder create() {
178      return new Builder();
179   }
180
181   private final int[] ports;
182   private final String jettyXml;
183   private final Boolean jettyXmlResolveVars;
184   private final Duration stopTimeout;
185   private final Duration shutdownSettleDelay;
186
187   JettySettings(Builder b) {
188      ports = b.ports;
189      jettyXml = b.jettyXml;
190      jettyXmlResolveVars = b.jettyXmlResolveVars;
191      stopTimeout = b.stopTimeout;
192      shutdownSettleDelay = b.shutdownSettleDelay;
193   }
194
195   /**
196    * Returns the candidate ports to try when binding the Jetty server, in priority order.
197    *
198    * @return The ports, or <jk>null</jk> if not set.
199    */
200   public int[] getPorts() {
201      return cp(ports);
202   }
203
204   /**
205    * Returns the raw <c>jetty.xml</c> contents to use when building the server.
206    *
207    * @return The XML contents, or <jk>null</jk> if not set.
208    */
209   public String getJettyXml() {
210      return jettyXml;
211   }
212
213   /**
214    * Returns whether SVL variables in the <c>jetty.xml</c> file should be resolved.
215    *
216    * @return The resolve-vars flag, or <jk>null</jk> if not set.
217    */
218   public Boolean getJettyXmlResolveVars() {
219      return jettyXmlResolveVars;
220   }
221
222   /**
223    * Returns the bounded graceful-shutdown drain timeout for the Jetty server.
224    *
225    * @return The drain timeout, or <jk>null</jk> if not set.
226    */
227   public Duration getStopTimeout() {
228      return stopTimeout;
229   }
230
231   /**
232    * Returns the settle delay applied between flipping the readiness probe out of service and stopping the connector.
233    *
234    * @return The settle delay, or <jk>null</jk> if not set.
235    */
236   public Duration getShutdownSettleDelay() {
237      return shutdownSettleDelay;
238   }
239}