001/*
002 * #%L
003 * HAPI FHIR - Server Framework
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.rest.api.server;
021
022import jakarta.annotation.Nonnull;
023import jakarta.annotation.Nullable;
024
025import java.io.Closeable;
026import java.io.IOException;
027import java.io.OutputStream;
028import java.io.Writer;
029import java.util.List;
030import java.util.Map;
031
032/**
033 * Implementations of this interface represent a response back to the client from the server. It is
034 * conceptually similar to {@link jakarta.servlet.http.HttpServletResponse} but intended to be agnostic
035 * of the server framework being used.
036 * <p>
037 * This class is a bit of an awkward abstraction given the two styles of servers it supports.
038 * Servlets work by writing to a servlet response that is provided as a parameter by the container. JAX-RS
039 * works by returning an object via a method return back to the containing framework. However using it correctly should
040 * make for compatible code across both approaches.
041 * </p>
042 */
043public interface IRestfulResponse {
044
045        /**
046         * Initiate a new textual response. The Writer returned by this method must be finalized by
047         * calling {@link #commitResponse(Closeable)} later.
048         * <p>
049         * Note that the caller should not close the returned object, but should instead just
050         * return it to {@link #commitResponse(Closeable)} upon successful completion. This is
051         * different from normal Java practice where you would request it in a <code>try with resource</code>
052         * block, since in Servlets you are not actually required to close the writer/stream, and
053         * doing so automatically may prevent you from correctly handling exceptions.
054         * </p>
055         *
056         * @param theStatusCode  The HTTP status code.
057         * @param theContentType The HTTP response content type.
058         * @param theCharset     The HTTP response charset.
059         * @param theRespondGzip Should the response be GZip encoded?
060         * @return Returns a {@link Writer} that can accept the response body.
061         */
062        @Nonnull
063        Writer getResponseWriter(int theStatusCode, String theContentType, String theCharset, boolean theRespondGzip)
064                        throws IOException;
065
066        /**
067         * Initiate a new binary response. The OutputStream returned by this method must be finalized by
068         * calling {@link #commitResponse(Closeable)} later. This method should only be used for non-textual
069         * responses, for those use {@link #getResponseWriter(int, String, String, boolean)}.
070         * <p>
071         * Note that the caller should not close the returned object, but should instead just
072         * return it to {@link #commitResponse(Closeable)} upon successful completion. This is
073         * different from normal Java practice where you would request it in a <code>try with resource</code>
074         * block, since in Servlets you are not actually required to close the writer/stream, and
075         * doing so automatically may prevent you from correctly handling exceptions.
076         * </p>
077         *
078         * @param theStatusCode    The HTTP status code.
079         * @param theContentType   The HTTP response content type.
080         * @param theContentLength If known, the number of bytes that will be written. {@literal null} otherwise.
081         * @return Returns an {@link OutputStream} that can accept the response body.
082         */
083        @Nonnull
084        OutputStream getResponseOutputStream(int theStatusCode, String theContentType, @Nullable Integer theContentLength)
085                        throws IOException;
086
087        /**
088         * Finalizes the response streaming using the writer that was returned by calling either
089         * {@link #getResponseWriter(int, String, String, boolean)} or
090         * {@link #getResponseOutputStream(int, String, Integer)}. This method should only be
091         * called if the response writing/streaming actually completed successfully. If an error
092         * occurred you do not need to commit the response.
093         *
094         * @param theWriterOrOutputStream The {@link Writer} or {@link OutputStream} that was returned by this object, or a Writer/OutputStream
095         *                                which decorates the one returned by this object.
096         * @return If the server style requires a returned response object (i.e. JAX-RS Server), this method
097         * returns that object. If the server style does not require one (i.e. {@link ca.uhn.fhir.rest.server.RestfulServer}),
098         * this method returns {@literal null}.
099         */
100        Object commitResponse(@Nonnull Closeable theWriterOrOutputStream) throws IOException;
101
102        /**
103         * Adds a response header. This method must be called prior to calling
104         * {@link #getResponseWriter(int, String, String, boolean)} or {@link #getResponseOutputStream(int, String, Integer)}.
105         *
106         * @param headerKey   The header name
107         * @param headerValue The header value
108         */
109        void addHeader(String headerKey, String headerValue);
110
111        /**
112         * Returns the headers added to this response
113         */
114        Map<String, List<String>> getHeaders();
115}