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.rest.server.servlet;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.util.concurrent.atomic.*;
022import java.util.function.*;
023import java.util.logging.*;
024
025import org.apache.juneau.commons.logging.RichLogger;
026import org.apache.juneau.http.response.*;
027import org.apache.juneau.rest.server.*;
028
029import jakarta.servlet.*;
030import jakarta.servlet.http.*;
031
032/**
033 * Identical to {@link RestServlet} but doesn't extend from {@link HttpServlet}.
034 *
035 * <p>
036 * This is particularly useful in Spring Boot environments that auto-detect servlets to deploy in servlet containers,
037 * but you want this resource to be deployed as a child instead.
038 *
039 * <h5 class='section'>See Also:</h5><ul>
040 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestAnnotatedClasses">@Rest-Annotated Class</a>
041 * </ul>
042 */
043public abstract class RestResource {
044
045   private final AtomicReference<RestContext> context = new AtomicReference<>();
046
047   /**
048    * The programmatic configuration builder stashed on this instance, or <jk>null</jk> when the
049    * resource was constructed without a builder.  Mutable so it can be written by either the
050    * {@link #RestResource(RestBuilder)} constructor or {@link Builder#build()}.  Read non-reflectively by
051    * {@link RestContext} during construction so builder-supplied values take precedence over {@code @Rest}
052    * annotation values.
053    */
054   RestBuilder<?> restBuilder;
055
056   /**
057    * Default constructor.
058    */
059   protected RestResource() {}
060
061   /**
062    * Builder-injection constructor.
063    *
064    * @param builder The programmatic configuration builder.  May be <jk>null</jk>.
065    */
066   protected RestResource(RestBuilder<?> builder) {
067      this.restBuilder = builder;
068   }
069
070   /**
071    * Returns the programmatic configuration builder stashed on this resource, or <jk>null</jk> if none.
072    *
073    * @return The stashed builder, or <jk>null</jk> if none was injected.
074    */
075   @SuppressWarnings({
076      "java:S1452" // RestBuilder<?> wildcard return intentional; concrete builder type varies by REST resource class
077   })
078   public RestBuilder<?> getRestBuilder() {
079      return restBuilder;
080   }
081
082   /**
083    * Creates a new fluent builder for programmatically configuring an instance of the specified resource type.
084    *
085    * @param <R> The resource type.
086    * @param type The resource type to build.  Must not be <jk>null</jk>.
087    * @return A new builder.
088    */
089   public static <R extends RestResource> DefaultBuilder<R> builder(Class<R> type) {
090      return new DefaultBuilder<>(type);
091   }
092
093   /**
094    * Returns the current thread-local HTTP request.
095    *
096    * @return The current thread-local HTTP request, or <jk>null</jk> if it wasn't created.
097    */
098   public synchronized RestRequest getRequest() { return getContext().getLocalSession().getOpSession().getRequest(); }
099
100   /**
101    * Returns the current thread-local HTTP response.
102    *
103    * @return The current thread-local HTTP response, or <jk>null</jk> if it wasn't created.
104    */
105   public synchronized RestResponse getResponse() { return getContext().getLocalSession().getOpSession().getResponse(); }
106
107   /**
108    * Log a message.
109    *
110    * <p>
111    * Subclasses can intercept the handling of these messages by overriding {@link #doLog(Level, Throwable, Supplier)}.
112    *
113    * @param level The log level.
114    * @param msg The message to log.
115    * @param args Optional {@link String#format(String, Object...) String.format}-style arguments.
116    */
117   public void log(Level level, String msg, Object...args) {
118      doLog(level, null, fs(msg, args));
119   }
120
121   /**
122    * Log a message.
123    *
124    * <p>
125    * Subclasses can intercept the handling of these messages by overriding {@link #doLog(Level, Throwable, Supplier)}.
126    *
127    * @param level The log level.
128    * @param cause The cause.
129    * @param msg The message to log.
130    * @param args Optional {@link String#format(String, Object...) String.format}-style arguments.
131    */
132   public void log(Level level, Throwable cause, String msg, Object...args) {
133      doLog(level, cause, fs(msg, args));
134   }
135
136   /**
137    * Main logger method.
138    *
139    * <p>
140    * The default behavior logs a message to the Java logger of the class name.
141    *
142    * <p>
143    * Subclasses can override this method to implement their own logger handling.
144    *
145    * @param level The log level.
146    * @param cause Optional throwable.
147    * @param msg The message to log.
148    */
149   protected void doLog(Level level, Throwable cause, Supplier<String> msg) {
150      var c = context.get();
151      var logger = c == null ? null : c.getLogger();
152      if (logger == null)
153         logger = RichLogger.getLogger(cn(this));
154      logger.log(level, cause, msg);
155   }
156
157   /**
158    * Returns the read-only context object that contains all the configuration information about this resource.
159    *
160    * @return The context information on this servlet.
161    */
162   protected RestContext getContext() {
163      if (context.get() == null)
164         throw new InternalServerError("RestContext object not set on resource.");
165      return context.get();
166   }
167
168   /**
169    * Returns the runtime-overridden top-level mount paths for this resource.
170    *
171    * <p>
172    * Subclasses can override this method to substitute the {@code @Rest(paths)} annotation defaults at
173    * construction time. This is the &quot;getter&quot; rung in the runtime-override resolution chain
174    * documented on {@link RestContext#getPaths()}:
175    * <ol>
176    *    <li>Programmatic ({@code RestContext.Builder.paths(String...)}) &mdash; highest precedence.
177    *    <li>This {@code getPaths()} getter (when non-{@code null}).
178    *    <li>{@code @Rest(paths={...})} annotation default (SVL-resolved per element, comma-split) &mdash;
179    *       lowest precedence.
180    * </ol>
181    *
182    * <h5 class='section'>Accepted return shapes:</h5><ul>
183    *    <li>{@code null} &mdash; no override; resolution falls through to the {@code @Rest(paths=...)}
184    *       annotation default.
185    *    <li>{@link String} &mdash; a single path or a comma-delimited list, e.g.
186    *       {@code "/healthz,/readyz"}.
187    *    <li>{@code String[]} &mdash; each element may itself be a comma-delimited list.
188    *    <li>{@link java.util.Collection Collection}, {@link java.util.List List},
189    *       {@link java.util.Set Set}, {@link Iterable}, or {@link java.util.stream.Stream Stream}
190    *       of any of the above (nested mixes are recursively flattened).
191    *    <li>Primitive arrays (boxed during flattening).
192    * </ul>
193    *
194    * <p>
195    * Non-{@link String} leaves are coerced via {@link String#valueOf(Object)}.  Each leaf string then runs
196    * through the same per-element pipeline used for {@code @Rest(paths=...)} annotation elements: SVL is
197    * applied via the bean-store-backed {@link org.apache.juneau.commons.svl.VarResolverSession VarResolverSession}
198    * (so {@code $C{key}} consults the live {@link org.apache.juneau.config.Config Config}, {@code $E{NAME,default}}
199    * and {@code $S{prop,default}} resolve through the bootstrap variable catalog), and the post-SVL value is
200    * comma-split with each piece trimmed and empty pieces dropped.
201    *
202    * <h5 class='section'>Notes:</h5><ul>
203    *    <li class='note'>
204    *       Returning {@code null} (the default) means &quot;inherit annotation&quot; &mdash; the next rung resolves.
205    *    <li class='note'>
206    *       Returning {@code new String[0]}, an empty collection, an empty string, or a blank string means
207    *       &quot;explicitly clear&quot; &mdash; no top-level mounts.
208    * </ul>
209    *
210    * @return The runtime-overridden mount paths in any accepted shape, or {@code null} to inherit the
211    *    annotation default.
212    * @since 10.0.0
213    */
214   public Object getPaths() { return null; }
215
216   /**
217    * Sets the context object for this servlet.
218    *
219    * @param context Sets the context object on this servlet.
220    * @throws ServletException If error occurred during post-initialiation.
221    */
222   protected void setContext(RestContext context) throws ServletException {
223      this.context.set(context);
224   }
225
226   /**
227    * Fluent builder for programmatically configuring a {@link RestResource} subclass.
228    *
229    * <p>
230    * Subclassable, self-typed (CRTP) flavor builder.  For the common (non-subclassed) case
231    * use {@link RestResource#builder(Class)} which returns the concrete {@link DefaultBuilder} leaf.
232    *
233    * @param <R> The resource type produced by {@link #build()}.
234    * @param <SELF> The concrete builder type (self type).
235    */
236   @SuppressWarnings({
237      "java:S119" // 'SELF' (CRTP self-type) is intentional and clearer than a single-letter name.
238   })
239   public static class Builder<R extends RestResource,SELF extends Builder<R,SELF>> extends AbstractRestBuilder<R,SELF> {
240
241      /**
242       * Constructor.
243       *
244       * @param type The resource type produced by {@link #build()}.  Must not be <jk>null</jk>.
245       */
246      protected Builder(Class<R> type) {
247         super(type);
248      }
249
250      @Override /* AbstractRestBuilder */
251      public R build() {
252         var r = createResource();
253         r.restBuilder = this;
254         return r;
255      }
256   }
257
258   /**
259    * Concrete default leaf builder returned by {@link RestResource#builder(Class)} for the common (non-subclassed)
260    * case.
261    *
262    * @param <R> The resource type produced by {@link #build()}.
263    */
264   public static final class DefaultBuilder<R extends RestResource> extends Builder<R,DefaultBuilder<R>> {
265      DefaultBuilder(Class<R> type) {
266         super(type);
267      }
268   }
269}