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