001    package com.thetransactioncompany.jsonrpc2.client;
002    
003    
004    import java.io.BufferedReader;
005    import java.io.InputStream;
006    import java.io.InputStreamReader;
007    import java.io.IOException;
008    
009    import java.net.HttpURLConnection;
010    
011    import java.util.List;
012    import java.util.Map;
013    
014    import java.util.zip.GZIPInputStream;
015    import java.util.zip.Inflater;
016    import java.util.zip.InflaterInputStream;
017    
018    
019    /**
020     * Represents the raw HTTP response to a JSON-RPC 2.0 request or notification. 
021     * Can be used to retrieve the unparsed response content and headers.
022     *
023     * @since 1.6
024     * @author Vladimir Dzhuvinov
025     */
026    public class RawResponse {
027    
028    
029            /**
030             * The HTTP response headers.
031             */
032            private Map<String,List<String>> headers;
033            
034            
035            /**
036             * The HTTP response code.
037             */
038            private int statusCode;
039            
040            
041            /**
042             * The HTTP response message.
043             */
044            private String statusMessage;
045    
046    
047            /**
048             * The content length.
049             */
050            private int contentLength;
051    
052    
053            /**
054             * The content type.
055             */
056            private String contentType;
057    
058    
059            /**
060             * The content encoding.
061             */
062            private String contentEncoding;
063    
064    
065            /**
066             * The raw HTTP response content.
067             */
068            private String content;
069    
070    
071            /**
072             * No public instantiation.
073             */
074            private RawResponse() {}
075    
076    
077            /**
078             * Parses the raw HTTP response from the specified URL connection.
079             * 
080             * @param connection The URL connection, must be in state completed and 
081             *                   not {@code null}.
082             * 
083             * @throws IOException If the response content couldn't be read.
084             */
085            protected static RawResponse parse(final HttpURLConnection connection)
086                    throws IOException {
087    
088                    // Check for HTTP compression
089                    String encoding = connection.getContentEncoding();
090    
091                    InputStream is;
092    
093                    if (encoding != null && encoding.equalsIgnoreCase("gzip"))
094                            is = new GZIPInputStream(connection.getInputStream());
095    
096                    else if (encoding != null && encoding.equalsIgnoreCase("deflate"))
097                            is = new InflaterInputStream(connection.getInputStream(), new Inflater(true));
098    
099                    else
100                            is = connection.getInputStream();
101    
102    
103                    // Read the response content
104                    StringBuilder responseText = new StringBuilder();
105    
106                    BufferedReader input = new BufferedReader(new InputStreamReader(is, "UTF-8"));
107    
108                    String line;
109    
110                    while ((line = input.readLine()) != null) {
111                            responseText.append(line);
112                            responseText.append(System.getProperty("line.separator"));
113                    }
114    
115                    input.close();
116    
117                    RawResponse response = new RawResponse();
118    
119                    response.content = responseText.toString();
120                    
121                    // Save HTTP code + message
122                    response.statusCode = connection.getResponseCode();
123                    response.statusMessage = connection.getResponseMessage();
124    
125                    // Save headers
126                    response.headers = connection.getHeaderFields();
127    
128                    response.contentLength = connection.getContentLength();
129                    response.contentType = connection.getContentType();
130                    response.contentEncoding = encoding;
131    
132                    return response;
133            }
134            
135            
136            /**
137             * Gets the status code from the HTTP response message, e.g. 200 on 
138             * success.
139             * 
140             * @return The HTTP status code, or -1.
141             */
142            public int getStatusCode() {
143                    
144                    return statusCode;
145            }
146            
147            
148            /**
149             * Gets the HTTP response status message, if any, returned along with 
150             * the status code from a server.
151             *  
152             * @return The HTTP status message, or {@code null}.
153             */
154            public String getStatusMessage() {
155                    
156                    return statusMessage;
157            }
158    
159    
160            /**
161             * Returns the raw response content.
162             * 
163             * @return The raw content.
164             */
165            public String getContent() {
166    
167                    return content;
168            }
169            
170            
171            /**
172             * Returns an unmodifiable Map of the header fields. The Map keys are 
173             * Strings that represent the response header field names. Each Map 
174             * value is an unmodifiable List of Strings that represents the 
175             * corresponding field values.
176             * 
177             * @return A Map of the header fields.
178             */
179            public Map<String,List<String>> getHeaderFields() {
180                    
181                    return headers;
182            }
183    
184    
185            /**
186             * Returns the value of the named header field. If called on a 
187             * connection that sets the same header multiple times with possibly 
188             * different values, only the last value is returned.
189             *  
190             * @param name The name of the header.
191             * 
192             * @return The value of the named header field, {@code null} if there 
193             *         is no such field in the header.
194             */
195            public String getHeaderField(final String name) {
196    
197                    List <String> values = headers.get(name);
198    
199                    if (values == null | values.size() <= 0)
200                            return null;
201    
202                    return values.get(0);
203            }
204    
205    
206            /**
207             * Returns the value of the "Content-Length" header field. 
208             * 
209             * @return The content length of the response, or -1 if the content 
210             *         length  is not known.
211             */
212            public int getContentLength() {
213    
214                    return contentLength;
215            }
216    
217    
218            /**
219             * Returns the value of the "Content-Type" header field.
220             * 
221             * @return The content type of the response, or {@code null} if not 
222             *         known.
223             */
224            public String getContentType() {
225    
226                    return contentType;
227            }
228    
229            /**
230             * Returns the value of the "Content-Encoding" header field.
231             * 
232             * @return The content encoding of the response, or {@code null} if not 
233             *         known.
234             */
235            public String getContentEncoding() {
236    
237                    return contentEncoding;
238            }
239    }