001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest.servlet;
014
015import static org.apache.juneau.internal.ClassUtils.*;
016
017import java.text.*;
018import java.util.concurrent.atomic.*;
019import java.util.function.*;
020import java.util.logging.*;
021
022import jakarta.servlet.*;
023import jakarta.servlet.http.*;
024
025import org.apache.juneau.common.internal.*;
026import org.apache.juneau.http.response.*;
027import org.apache.juneau.rest.*;
028
029/**
030 * Identical to {@link RestServlet} but doesn't extend from {@link HttpServlet}.
031 *
032 * <p>
033 * This is particularly useful in Spring Boot environments that auto-detect servlets to deploy in servlet containers,
034 * but you want this resource to be deployed as a child instead.
035 *
036 * <h5 class='section'>See Also:</h5><ul>
037 *    <li class='link'><a class="doclink" href="../../../../../index.html#jrs.AnnotatedClasses">@Rest-Annotated Classes</a>
038 * </ul>
039 */
040public abstract class RestObject {
041
042   private AtomicReference<RestContext> context = new AtomicReference<>();
043
044   //-----------------------------------------------------------------------------------------------------------------
045   // Context methods.
046   //-----------------------------------------------------------------------------------------------------------------
047
048   /**
049    * Sets the context object for this servlet.
050    *
051    * @param context Sets the context object on this servlet.
052    * @throws ServletException If error occurred during post-initialiation.
053    */
054   protected void setContext(RestContext context) throws ServletException {
055      this.context.set(context);
056   }
057
058   /**
059    * Returns the read-only context object that contains all the configuration information about this resource.
060    *
061    * @return The context information on this servlet.
062    */
063   protected RestContext getContext() {
064      if (context.get() == null)
065         throw new InternalServerError("RestContext object not set on resource.");
066      return context.get();
067   }
068
069   //-----------------------------------------------------------------------------------------------------------------
070   // Convenience logger methods
071   //-----------------------------------------------------------------------------------------------------------------
072
073   /**
074    * Log a message.
075    *
076    * <p>
077    * Subclasses can intercept the handling of these messages by overriding {@link #doLog(Level, Throwable, Supplier)}.
078    *
079    * @param level The log level.
080    * @param msg The message to log.
081    * @param args Optional {@link MessageFormat}-style arguments.
082    */
083   public void log(Level level, String msg, Object...args) {
084      doLog(level, null, () -> StringUtils.format(msg, args));
085   }
086
087   /**
088    * Log a message.
089    *
090    * <p>
091    * Subclasses can intercept the handling of these messages by overriding {@link #doLog(Level, Throwable, Supplier)}.
092    *
093    * @param level The log level.
094    * @param cause The cause.
095    * @param msg The message to log.
096    * @param args Optional {@link MessageFormat}-style arguments.
097    */
098   public void log(Level level, Throwable cause, String msg, Object...args) {
099      doLog(level, cause, () -> StringUtils.format(msg, args));
100   }
101
102   /**
103    * Main logger method.
104    *
105    * <p>
106    * The default behavior logs a message to the Java logger of the class name.
107    *
108    * <p>
109    * Subclasses can override this method to implement their own logger handling.
110    *
111    * @param level The log level.
112    * @param cause Optional throwable.
113    * @param msg The message to log.
114    */
115   protected void doLog(Level level, Throwable cause, Supplier<String> msg) {
116      RestContext c = context.get();
117      Logger logger = c == null ? null : c.getLogger();
118      if (logger == null)
119         logger = Logger.getLogger(className(this));
120      logger.log(level, cause, msg);
121   }
122
123   //-----------------------------------------------------------------------------------------------------------------
124   // Other methods
125   //-----------------------------------------------------------------------------------------------------------------
126
127   /**
128    * Returns the current thread-local HTTP request.
129    *
130    * @return The current thread-local HTTP request, or <jk>null</jk> if it wasn't created.
131    */
132   public synchronized RestRequest getRequest() {
133      return getContext().getLocalSession().getOpSession().getRequest();
134   }
135
136   /**
137    * Returns the current thread-local HTTP response.
138    *
139    * @return The current thread-local HTTP response, or <jk>null</jk> if it wasn't created.
140    */
141   public synchronized RestResponse getResponse() {
142      return getContext().getLocalSession().getOpSession().getResponse();
143   }
144}