Add ability to see raw response from server when something goes wrong. (OC Transpo...
[frank.git] / prod / net / jaekl / qd / http / RequestBroker.java
1 // Copyright (C) 2004, 2014 Christian Jaekl
2
3 package net.jaekl.qd.http;
4
5 import java.io.BufferedReader;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.io.InputStreamReader;
9 import java.io.UnsupportedEncodingException;
10 import java.lang.reflect.InvocationTargetException;
11 import java.nio.charset.Charset;
12 import java.util.ArrayList;
13
14 import net.jaekl.qd.QDException;
15 import net.jaekl.qd.util.ExceptionUtils;
16 import net.jaekl.qd.util.InputStreamWrapper;
17 import net.jaekl.qd.xml.ParseErrorHandler;
18 import net.jaekl.qd.xml.ParseHandler;
19 import net.jaekl.qd.xml.ParseResult;
20
21 import org.apache.http.HttpEntity;
22 import org.apache.http.HttpResponse;
23 import org.apache.http.NameValuePair;
24 import org.apache.http.client.HttpClient;
25 import org.apache.http.client.config.RequestConfig;
26 import org.apache.http.client.entity.UrlEncodedFormEntity;
27 import org.apache.http.client.methods.HttpPost;
28 import org.apache.http.impl.client.HttpClientBuilder;
29 import org.xml.sax.InputSource;
30 import org.xml.sax.SAXException;
31 import org.xml.sax.SAXParseException;
32 import org.xml.sax.XMLReader;
33 import org.xml.sax.helpers.XMLReaderFactory;
34
35 public class RequestBroker
36 {
37         final String UTF_8 = "UTF-8";
38         final int TIMEOUT_MSEC = 5000;  // Allow at most 5 seconds before we declare the server to be unresponsive
39         
40         String m_gatewayUrl;
41         ArrayList<NameValuePair> m_baseParams;
42
43         public RequestBroker(String gatewayUrl, ArrayList<NameValuePair> baseParams)
44         {
45                 m_gatewayUrl = gatewayUrl;
46                 m_baseParams = new ArrayList<NameValuePair>(baseParams);
47         }
48         
49         // NB:  Caller is responsible for close()ing the returned InputStream
50         //
51         InputStream doSubmit(String method, ArrayList<NameValuePair> passedParams) throws QDException
52         {
53                 ArrayList<NameValuePair> params = new ArrayList<NameValuePair>(m_baseParams);
54                 params.addAll(passedParams);
55                 
56                 try {
57                         RequestConfig.Builder requestBuilder = RequestConfig.custom();
58                         requestBuilder = requestBuilder.setConnectTimeout(TIMEOUT_MSEC);
59                         requestBuilder = requestBuilder.setSocketTimeout(TIMEOUT_MSEC);
60                         HttpClientBuilder builder = HttpClientBuilder.create();
61                         builder.setDefaultRequestConfig(requestBuilder.build());
62                         HttpClient httpClient = builder.build(); 
63                         HttpPost httpPost = new HttpPost(m_gatewayUrl + "/" + method + "/");
64                         httpPost.setEntity(new UrlEncodedFormEntity(params, UTF_8));
65                         HttpResponse response = httpClient.execute(httpPost);
66                         HttpEntity entity = response.getEntity();
67
68                         if (null != entity) {
69                                 InputStream is = entity.getContent();
70                                 return is;
71                         }
72                 }
73                 catch (UnsupportedEncodingException uee) {
74                         // We should actually be guaranteed that this never happens, 
75                         // because all JVMs are required to support UTF-8
76                         assert(false);
77                         throw new Error(uee);
78                 }
79                 catch (IOException ioe) {
80                         throw new QDException(ioe);
81                 }
82                 
83                 return null;
84         }
85
86         public String submit(String method, ArrayList<NameValuePair> passedParams) throws QDException
87         {
88                 StringBuilder sb = new StringBuilder();
89                 InputStream is = null;
90
91                 try {
92                         is = doSubmit(method, passedParams);
93                         BufferedReader br = new BufferedReader(new InputStreamReader(is));
94                         String line = br.readLine();
95                         while (null != line) {
96                                 sb.append(line).append("\n");
97                                 line = br.readLine();
98                         }
99                 }
100                 catch (IOException ioe) {
101                         throw new QDException(ioe);
102                 }
103                 finally {
104                         ExceptionUtils.tryClose(is);
105                 }
106
107                 return sb.toString();
108         }
109         
110         public ParseResult submitAndParse(String method, 
111                           ArrayList<NameValuePair> passedParams, 
112                           Class<? extends ParseResult> rootParserClass)
113         throws QDException
114         {
115                 return submitAndParse(method, passedParams, rootParserClass, null);
116         }
117         
118         public ParseResult submitAndParse(String method, 
119                                                                           ArrayList<NameValuePair> passedParams, 
120                                                                           Class<? extends ParseResult> rootParserClass,
121                                                                           String rootTagName)
122         throws QDException
123         {
124                 ParseResult result = null;
125                 InputStreamWrapper isw = null;
126                 Charset utf8 = null;
127                 
128                 try {
129                         utf8 = Charset.forName(UTF_8);
130                         if (null == rootTagName) {
131                                 result = (ParseResult) rootParserClass.newInstance();
132                         } 
133                         else {
134                                 result = (ParseResult) rootParserClass.getDeclaredConstructor(String.class).newInstance(rootTagName);
135                         }
136                         isw = new InputStreamWrapper(doSubmit(method, passedParams));
137                         XMLReader reader = XMLReaderFactory.createXMLReader();
138                         ParseHandler ph = new ParseHandler(result);
139                         ParseErrorHandler peh = new ParseErrorHandler();
140                         reader.setContentHandler(ph);
141                         reader.setErrorHandler(peh);
142                         reader.parse(new InputSource(isw));
143                 } 
144                 catch ( SAXParseException saxpe ) {
145                         String response = "<n/a>";
146                         if (null != isw) {
147                                 response = new String(isw.getHeadBytes(), utf8);
148                         }
149                         throw new InvalidResponseException(saxpe, m_gatewayUrl, method, response);
150                 }
151                 catch ( InstantiationException
152                                 | InvocationTargetException
153                                 | IllegalAccessException
154                                 | IOException 
155                                 | NoSuchMethodException
156                                 | SAXException 
157                                 e )
158                 {
159                         throw new QDException(e);
160                 } 
161                 finally {
162                         ExceptionUtils.tryClose(isw);
163                 }
164                 
165                 return result;
166         }
167 }