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