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;
014
015import java.io.*;
016
017import org.apache.http.*;
018import org.apache.juneau.*;
019import org.apache.juneau.cp.*;
020import org.apache.juneau.http.response.*;
021import org.apache.juneau.rest.converter.*;
022import org.apache.juneau.rest.guard.*;
023import org.apache.juneau.rest.logger.*;
024
025/**
026 * A session for a single HTTP request.
027 *
028 * <p>
029 * This session object gets created by {@link RestSession} once the Java method to be invoked has been determined.
030 *
031 * <h5 class='section'>Notes:</h5><ul>
032 *    <li class='warn'>This class is not thread safe.
033 * </ul>
034 *
035 * <h5 class='section'>See Also:</h5><ul>
036 * </ul>
037 */
038public class RestOpSession extends ContextSession {
039
040
041   //-----------------------------------------------------------------------------------------------------------------
042   // Static
043   //-----------------------------------------------------------------------------------------------------------------
044
045   /**
046    * Static creator.
047    *
048    * @param ctx The context object of the Java method being invoked.
049    * @param session The REST session object creating this object.
050    * @return A new builder.
051    */
052   public static Builder create(RestOpContext ctx, RestSession session) {
053      return new Builder(ctx, session);
054   }
055
056   //-----------------------------------------------------------------------------------------------------------------
057   // Builder
058   //-----------------------------------------------------------------------------------------------------------------
059
060   /**
061    * Builder class.
062    */
063   public static class Builder extends ContextSession.Builder {
064
065      final RestOpContext ctx;
066      final RestSession session;
067
068      /**
069       * Constructor.
070       *
071       * @param ctx The context object of the Java method being invoked.
072       * @param session The REST session object creating this object.
073       */
074      public Builder(RestOpContext ctx, RestSession session) {
075         super(ctx);
076         this.ctx = ctx;
077         this.session = session;
078      }
079
080      /**
081       * Sets the logger to use when logging this call.
082       *
083       * @param value The new value for this setting.  Can be <jk>null</jk>.
084       * @return This object.
085       */
086      public Builder logger(CallLogger value) {
087         session.logger(value);
088         return this;
089      }
090
091      /**
092       * Enables or disabled debug mode on this call.
093       *
094       * @param value The new value for this setting.
095       * @return This object.
096       * @throws IOException Occurs if request content could not be cached into memory.
097       */
098      public Builder debug(boolean value) throws IOException {
099         session.debug(value);
100         return this;
101      }
102
103      @Override /* Session.Builder */
104      public RestOpSession build() {
105         return new RestOpSession(this);
106      }
107   }
108
109   //-----------------------------------------------------------------------------------------------------------------
110   // Instance
111   //-----------------------------------------------------------------------------------------------------------------
112
113   private final RestOpContext ctx;
114   private final RestSession session;
115   private final RestRequest req;
116   private final RestResponse res;
117
118   /**
119    * Constructor.
120    *
121    * @param builder The builder for this object.
122    */
123   protected RestOpSession(Builder builder) {
124      super(builder);
125      ctx = builder.ctx;
126      session = builder.session;
127      try {
128         req = session.getBeanStore().add(RestRequest.class, ctx.createRequest(session));
129         res = session.getBeanStore().add(RestResponse.class, ctx.createResponse(session, req));
130      } catch (RuntimeException e) {
131         throw e;
132      } catch (Exception e) {
133         throw new InternalServerError(e);
134      }
135   }
136
137   @Override /* ContextSession */
138   public RestOpContext getContext() {
139      return ctx;
140   }
141
142   /**
143    * Runs this session.
144    *
145    * <p>
146    * Does the following:
147    * <ol>
148    *    <li>Runs the guards on the method.
149    *    <li>Finds the parameter values to pass to the Java method.
150    *    <li>Invokes the Java method.
151    *    <li>Sets the output and status on the response.
152    *    <li>Calls the converters on the Java method.
153    * </ol>
154    *
155    * @throws Throwable Any throwable can be thrown.
156    */
157   public void run() throws Throwable {
158
159      for (RestGuard guard : ctx.getGuards())
160         if (! guard.guard(req, res))
161            return;
162
163      ctx.getMethodInvoker().invoke(this);
164
165      if (res.hasContent())
166         for (RestConverter converter : ctx.getConverters())
167            res.setContent(converter.convert(req, res.getContent().orElse(null)));
168   }
169
170   /**
171    * Returns the REST request object for this session.
172    *
173    * @return The REST request object for this session.
174    */
175   public RestRequest getRequest() {
176      return req;
177   }
178
179   /**
180    * Returns the REST response object for this session.
181    *
182    * @return The REST response object for this session.
183    */
184   public RestResponse getResponse() {
185      return res;
186   }
187
188   /**
189    * Returns the bean store for this session.
190    *
191    * @return The bean store for this session.
192    */
193   public BeanStore getBeanStore() {
194      return session.getBeanStore();
195   }
196
197   /**
198    * Returns the context of the parent class of this Java method.
199    *
200    * @return The context of the parent class of this Java method.
201    */
202   public RestContext getRestContext() {
203      return session.getContext();
204   }
205
206   /**
207    * Returns the session of the parent class of this Java method.
208    *
209    * @return The session of the parent class of this Java method.
210    */
211   public RestSession getRestSession() {
212      return session;
213   }
214
215   /**
216    * Sets the status of the response.
217    *
218    * @param value The new status.
219    * @return This object.
220    */
221   public RestOpSession status(StatusLine value) {
222      session.status(value);
223      return this;
224   }
225
226   /**
227    * Called at the end of a call to finish any remaining tasks such as flushing buffers and logging the response.
228    *
229    * @return This object.
230    */
231   public RestOpSession finish() {
232      try {
233         res.flushBuffer();
234         req.close();
235      } catch (Exception e) {
236         session.exception(e);
237      }
238      return this;
239   }
240}