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.internal.ClassUtils.*;
020
021import java.text.*;
022import java.util.concurrent.atomic.*;
023import java.util.function.*;
024import java.util.logging.*;
025
026import org.apache.juneau.common.utils.*;
027import org.apache.juneau.http.response.*;
028import org.apache.juneau.rest.*;
029
030import jakarta.servlet.*;
031import jakarta.servlet.http.*;
032
033/**
034 * Identical to {@link RestServlet} but doesn't extend from {@link HttpServlet}.
035 *
036 * <p>
037 * This is particularly useful in Spring Boot environments that auto-detect servlets to deploy in servlet containers,
038 * but you want this resource to be deployed as a child instead.
039 *
040 * <h5 class='section'>See Also:</h5><ul>
041 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/RestAnnotatedClassBasics">@Rest-Annotated Class Basics</a>
042 * </ul>
043 */
044public abstract class RestObject {
045
046   private AtomicReference<RestContext> context = new AtomicReference<>();
047
048   //-----------------------------------------------------------------------------------------------------------------
049   // Context methods.
050   //-----------------------------------------------------------------------------------------------------------------
051
052   /**
053    * Sets the context object for this servlet.
054    *
055    * @param context Sets the context object on this servlet.
056    * @throws ServletException If error occurred during post-initialiation.
057    */
058   protected void setContext(RestContext context) throws ServletException {
059      this.context.set(context);
060   }
061
062   /**
063    * Returns the read-only context object that contains all the configuration information about this resource.
064    *
065    * @return The context information on this servlet.
066    */
067   protected RestContext getContext() {
068      if (context.get() == null)
069         throw new InternalServerError("RestContext object not set on resource.");
070      return context.get();
071   }
072
073   //-----------------------------------------------------------------------------------------------------------------
074   // Convenience logger methods
075   //-----------------------------------------------------------------------------------------------------------------
076
077   /**
078    * Log a message.
079    *
080    * <p>
081    * Subclasses can intercept the handling of these messages by overriding {@link #doLog(Level, Throwable, Supplier)}.
082    *
083    * @param level The log level.
084    * @param msg The message to log.
085    * @param args Optional {@link MessageFormat}-style arguments.
086    */
087   public void log(Level level, String msg, Object...args) {
088      doLog(level, null, () -> StringUtils.format(msg, args));
089   }
090
091   /**
092    * Log a message.
093    *
094    * <p>
095    * Subclasses can intercept the handling of these messages by overriding {@link #doLog(Level, Throwable, Supplier)}.
096    *
097    * @param level The log level.
098    * @param cause The cause.
099    * @param msg The message to log.
100    * @param args Optional {@link MessageFormat}-style arguments.
101    */
102   public void log(Level level, Throwable cause, String msg, Object...args) {
103      doLog(level, cause, () -> StringUtils.format(msg, args));
104   }
105
106   /**
107    * Main logger method.
108    *
109    * <p>
110    * The default behavior logs a message to the Java logger of the class name.
111    *
112    * <p>
113    * Subclasses can override this method to implement their own logger handling.
114    *
115    * @param level The log level.
116    * @param cause Optional throwable.
117    * @param msg The message to log.
118    */
119   protected void doLog(Level level, Throwable cause, Supplier<String> msg) {
120      RestContext c = context.get();
121      Logger logger = c == null ? null : c.getLogger();
122      if (logger == null)
123         logger = Logger.getLogger(className(this));
124      logger.log(level, cause, msg);
125   }
126
127   //-----------------------------------------------------------------------------------------------------------------
128   // Other methods
129   //-----------------------------------------------------------------------------------------------------------------
130
131   /**
132    * Returns the current thread-local HTTP request.
133    *
134    * @return The current thread-local HTTP request, or <jk>null</jk> if it wasn't created.
135    */
136   public synchronized RestRequest getRequest() {
137      return getContext().getLocalSession().getOpSession().getRequest();
138   }
139
140   /**
141    * Returns the current thread-local HTTP response.
142    *
143    * @return The current thread-local HTTP response, or <jk>null</jk> if it wasn't created.
144    */
145   public synchronized RestResponse getResponse() {
146      return getContext().getLocalSession().getOpSession().getResponse();
147   }
148}