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.servlet;
018
019import static org.apache.juneau.commons.utils.Utils.*;
020
021import java.text.*;
022import java.util.concurrent.atomic.*;
023import java.util.function.*;
024import java.util.logging.*;
025
026import org.apache.juneau.http.response.*;
027import org.apache.juneau.rest.*;
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/RestAnnotatedClassBasics">@Rest-Annotated Class Basics</a>
041 * </ul>
042 */
043public abstract class RestObject {
044
045   private AtomicReference<RestContext> context = new AtomicReference<>();
046
047   /**
048    * Returns the current thread-local HTTP request.
049    *
050    * @return The current thread-local HTTP request, or <jk>null</jk> if it wasn't created.
051    */
052   public synchronized RestRequest getRequest() { return getContext().getLocalSession().getOpSession().getRequest(); }
053
054   /**
055    * Returns the current thread-local HTTP response.
056    *
057    * @return The current thread-local HTTP response, or <jk>null</jk> if it wasn't created.
058    */
059   public synchronized RestResponse getResponse() { return getContext().getLocalSession().getOpSession().getResponse(); }
060
061   /**
062    * Log a message.
063    *
064    * <p>
065    * Subclasses can intercept the handling of these messages by overriding {@link #doLog(Level, Throwable, Supplier)}.
066    *
067    * @param level The log level.
068    * @param msg The message to log.
069    * @param args Optional {@link MessageFormat}-style arguments.
070    */
071   public void log(Level level, String msg, Object...args) {
072      doLog(level, null, fs(msg, args));
073   }
074
075   /**
076    * Log a message.
077    *
078    * <p>
079    * Subclasses can intercept the handling of these messages by overriding {@link #doLog(Level, Throwable, Supplier)}.
080    *
081    * @param level The log level.
082    * @param cause The cause.
083    * @param msg The message to log.
084    * @param args Optional {@link MessageFormat}-style arguments.
085    */
086   public void log(Level level, Throwable cause, String msg, Object...args) {
087      doLog(level, cause, fs(msg, args));
088   }
089
090   /**
091    * Main logger method.
092    *
093    * <p>
094    * The default behavior logs a message to the Java logger of the class name.
095    *
096    * <p>
097    * Subclasses can override this method to implement their own logger handling.
098    *
099    * @param level The log level.
100    * @param cause Optional throwable.
101    * @param msg The message to log.
102    */
103   protected void doLog(Level level, Throwable cause, Supplier<String> msg) {
104      var c = context.get();
105      var logger = c == null ? null : c.getLogger();
106      if (logger == null)
107         logger = Logger.getLogger(cn(this));
108      logger.log(level, cause, msg);
109   }
110
111   /**
112    * Returns the read-only context object that contains all the configuration information about this resource.
113    *
114    * @return The context information on this servlet.
115    */
116   protected RestContext getContext() {
117      if (context.get() == null)
118         throw new InternalServerError("RestContext object not set on resource.");
119      return context.get();
120   }
121
122   /**
123    * Sets the context object for this servlet.
124    *
125    * @param context Sets the context object on this servlet.
126    * @throws ServletException If error occurred during post-initialiation.
127    */
128   protected void setContext(RestContext context) throws ServletException {
129      this.context.set(context);
130   }
131}