001/* 002 * #%L 003 * HAPI FHIR JAX-RS Server 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.jaxrs.server.util; 021 022import ca.uhn.fhir.rest.api.Constants; 023import ca.uhn.fhir.rest.server.BaseRestfulResponse; 024import ca.uhn.fhir.util.IoUtil; 025import jakarta.annotation.Nonnull; 026import jakarta.ws.rs.core.Response; 027import jakarta.ws.rs.core.Response.ResponseBuilder; 028import org.apache.commons.lang3.StringUtils; 029import org.apache.commons.lang3.Validate; 030 031import java.io.ByteArrayOutputStream; 032import java.io.Closeable; 033import java.io.OutputStream; 034import java.io.StringWriter; 035import java.io.Writer; 036import java.util.List; 037import java.util.Map.Entry; 038 039import static org.apache.commons.lang3.StringUtils.isNotBlank; 040 041/** 042 * The JaxRsResponse is a jax-rs specific implementation of the RestfulResponse. 043 * 044 * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare 045 */ 046public class JaxRsResponse extends BaseRestfulResponse<JaxRsRequest> { 047 048 private StringWriter myWriter; 049 private int myStatusCode; 050 private String myContentType; 051 private String myCharset; 052 private ByteArrayOutputStream myOutputStream; 053 054 /** 055 * The constructor 056 * 057 * @param request the JaxRs Request 058 */ 059 public JaxRsResponse(JaxRsRequest request) { 060 super(request); 061 } 062 063 /** 064 * The response writer is a simple String Writer. All output is configured 065 * by the server. 066 */ 067 @Nonnull 068 @Override 069 public Writer getResponseWriter( 070 int theStatusCode, String theContentType, String theCharset, boolean theRespondGzip) { 071 Validate.isTrue(myWriter == null, "getResponseWriter() called multiple times"); 072 Validate.isTrue(myOutputStream == null, "getResponseWriter() called after getResponseOutputStream()"); 073 myWriter = new StringWriter(); 074 myStatusCode = theStatusCode; 075 myContentType = theContentType; 076 myCharset = theCharset; 077 return myWriter; 078 } 079 080 @Nonnull 081 @Override 082 public OutputStream getResponseOutputStream(int theStatusCode, String theContentType, Integer theContentLength) { 083 Validate.isTrue(myWriter == null, "getResponseOutputStream() called multiple times"); 084 Validate.isTrue(myOutputStream == null, "getResponseOutputStream() called after getResponseWriter()"); 085 086 myOutputStream = new ByteArrayOutputStream(); 087 myStatusCode = theStatusCode; 088 myContentType = theContentType; 089 090 return myOutputStream; 091 } 092 093 @Override 094 public Response commitResponse(@Nonnull Closeable theWriterOrOutputStream) { 095 IoUtil.closeQuietly(theWriterOrOutputStream); 096 097 ResponseBuilder builder = buildResponse(myStatusCode); 098 if (isNotBlank(myContentType)) { 099 if (myWriter != null) { 100 String charContentType = myContentType + "; charset=" 101 + StringUtils.defaultIfBlank(myCharset, Constants.CHARSET_NAME_UTF8); 102 builder.header(Constants.HEADER_CONTENT_TYPE, charContentType); 103 builder.entity(myWriter.toString()); 104 } else { 105 byte[] byteArray = myOutputStream.toByteArray(); 106 if (byteArray.length > 0) { 107 builder.header(Constants.HEADER_CONTENT_TYPE, myContentType); 108 builder.entity(byteArray); 109 } 110 } 111 } 112 113 Response retVal = builder.build(); 114 return retVal; 115 } 116 117 private ResponseBuilder buildResponse(int statusCode) { 118 ResponseBuilder response = Response.status(statusCode); 119 for (Entry<String, List<String>> header : getHeaders().entrySet()) { 120 final String key = header.getKey(); 121 for (String value : header.getValue()) { 122 response.header(key, value); 123 } 124 } 125 return response; 126 } 127}