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