001package ca.uhn.fhir.rest.client.apache;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2017 University Health Network
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 * 
013 * http://www.apache.org/licenses/LICENSE-2.0
014 * 
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import java.io.ByteArrayInputStream;
024import java.io.IOException;
025import java.io.InputStream;
026import java.io.InputStreamReader;
027import java.io.Reader;
028import java.io.StringReader;
029import java.nio.charset.Charset;
030import java.util.ArrayList;
031import java.util.Arrays;
032import java.util.HashMap;
033import java.util.List;
034import java.util.Map;
035
036import org.apache.commons.io.IOUtils;
037import org.apache.http.Header;
038import org.apache.http.HttpEntity;
039import org.apache.http.HttpResponse;
040import org.apache.http.client.methods.CloseableHttpResponse;
041import org.apache.http.entity.ContentType;
042
043import ca.uhn.fhir.rest.client.api.IHttpResponse;
044import ca.uhn.fhir.rest.server.Constants;
045import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
046
047/**
048 * A Http Response based on Apache. This is an adapter around the class
049 * {@link org.apache.http.HttpResponse HttpResponse}
050 * 
051 * @author Peter Van Houte | peter.vanhoute@agfa.com | Agfa Healthcare
052 */
053public class ApacheHttpResponse implements IHttpResponse {
054
055        private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ApacheHttpResponse.class);
056
057        private boolean myEntityBuffered = false;
058        private byte[] myEntityBytes;
059        private final HttpResponse myResponse;
060
061        public ApacheHttpResponse(HttpResponse theResponse) {
062                this.myResponse = theResponse;
063        }
064
065        @Deprecated // override deprecated method
066        @Override
067        public void bufferEntitity() throws IOException {
068                bufferEntity();
069        }
070
071        @Override
072        public void bufferEntity() throws IOException {
073                if (myEntityBuffered) {
074                        return;
075                }
076                InputStream respEntity = readEntity();
077                if (respEntity != null) {
078                        this.myEntityBuffered = true;
079                        try {
080                                this.myEntityBytes = IOUtils.toByteArray(respEntity);
081                        } catch (IllegalStateException e) {
082                                // FIXME resouce leak
083                                throw new InternalErrorException(e);
084                        }
085                }
086        }
087
088        @Override
089        public void close() {
090                if (myResponse instanceof CloseableHttpResponse) {
091                        try {
092                                ((CloseableHttpResponse) myResponse).close();
093                        } catch (IOException e) {
094                                ourLog.debug("Failed to close response", e);
095                        }
096                }
097        }
098
099        @Override
100        public Reader createReader() throws IOException {
101                HttpEntity entity = myResponse.getEntity();
102                if (entity == null) {
103                        return new StringReader("");
104                }
105                Charset charset = null;
106                if (entity.getContentType() != null && entity.getContentType().getElements() != null
107                                && entity.getContentType().getElements().length > 0) {
108                        ContentType ct = ContentType.get(entity);
109                        charset = ct.getCharset();
110                }
111                if (charset == null) {
112                        if (Constants.STATUS_HTTP_204_NO_CONTENT != myResponse.getStatusLine().getStatusCode()) {
113                                ourLog.warn("Response did not specify a charset.");
114                        }
115                        charset = Charset.forName("UTF-8");
116                }
117
118                Reader reader = new InputStreamReader(readEntity(), charset);
119                return reader;
120        }
121
122        @Override
123        public Map<String, List<String>> getAllHeaders() {
124                Map<String, List<String>> headers = new HashMap<String, List<String>>();
125                if (myResponse.getAllHeaders() != null) {
126                        for (Header next : myResponse.getAllHeaders()) {
127                                String name = next.getName().toLowerCase();
128                                List<String> list = headers.get(name);
129                                if (list == null) {
130                                        list = new ArrayList<String>();
131                                        headers.put(name, list);
132                                }
133                                list.add(next.getValue());
134                        }
135
136                }
137                return headers;
138        }
139
140        @Override
141        public List<String> getHeaders(String theName) {
142                Header[] headers = myResponse.getHeaders(theName);
143                if (headers == null) {
144                        headers = new Header[0];
145                }
146                List<String> retVal = new ArrayList<String>();
147                for (Header next : headers) {
148                        retVal.add(next.getValue());
149                }
150                return retVal;
151        }
152
153        @Override
154        public String getMimeType() {
155                ContentType ct = ContentType.get(myResponse.getEntity());
156                return ct != null ? ct.getMimeType() : null;
157        }
158
159        @Override
160        public HttpResponse getResponse() {
161                return myResponse;
162        }
163
164        @Override
165        public int getStatus() {
166                return myResponse.getStatusLine().getStatusCode();
167        }
168
169        @Override
170        public String getStatusInfo() {
171                return myResponse.getStatusLine().getReasonPhrase();
172        }
173
174        @Override
175        public InputStream readEntity() throws IOException {
176                if (this.myEntityBuffered) {
177                        return new ByteArrayInputStream(myEntityBytes);
178                } else if (myResponse.getEntity() != null) {
179                        return myResponse.getEntity().getContent();
180                } else {
181                        return null;
182                }
183        }
184}