OSDN Git Service

Added shinjuku library
[worldopac/WorldOpac.git] / WorldOpac / src / de / geeksfactory / opacclient / apis / BaseApi.java
1 /**
2  * Copyright (C) 2013 by Raphael Michel under the MIT license:
3  * 
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), 
6  * to deal in the Software without restriction, including without limitation 
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
8  * and/or sell copies of the Software, and to permit persons to whom the Software 
9  * is furnished to do so, subject to the following conditions:
10  * 
11  * The above copyright notice and this permission notice shall be included in 
12  * all copies or substantial portions of the Software.
13  * 
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
18  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
20  * DEALINGS IN THE SOFTWARE.
21  */
22 package de.geeksfactory.opacclient.apis;
23
24 import java.io.BufferedReader;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.io.InterruptedIOException;
29 import java.io.UnsupportedEncodingException;
30 import java.net.URLDecoder;
31 import java.net.UnknownHostException;
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36
37 import org.apache.http.HttpEntity;
38 import org.apache.http.HttpResponse;
39 import org.apache.http.MalformedChunkCodingException;
40 import org.apache.http.NameValuePair;
41 import org.apache.http.NoHttpResponseException;
42 import org.apache.http.client.ClientProtocolException;
43 import org.apache.http.client.CookieStore;
44 import org.apache.http.client.entity.UrlEncodedFormEntity;
45 import org.apache.http.client.methods.HttpGet;
46 import org.apache.http.client.methods.HttpPost;
47 import org.apache.http.client.protocol.ClientContext;
48 import org.apache.http.client.utils.URLEncodedUtils;
49 import org.apache.http.conn.ConnectTimeoutException;
50 import org.apache.http.impl.client.DefaultHttpClient;
51 import org.apache.http.message.BasicNameValuePair;
52 import org.apache.http.protocol.BasicHttpContext;
53 import org.apache.http.protocol.HttpContext;
54 import org.apache.http.util.EntityUtils;
55
56 import android.graphics.Bitmap;
57 import android.graphics.BitmapFactory;
58 import de.geeksfactory.opacclient.NotReachableException;
59 import de.geeksfactory.opacclient.networking.HTTPClient;
60 import de.geeksfactory.opacclient.objects.CoverHolder;
61 import de.geeksfactory.opacclient.objects.Library;
62 import de.geeksfactory.opacclient.storage.MetaDataSource;
63
64 /**
65  * Abstract Base class for OpacApi implementations providing some helper methods
66  * for HTTP
67  */
68 public abstract class BaseApi implements OpacApi {
69
70         protected DefaultHttpClient http_client;
71
72         /**
73          * Initializes HTTP client
74          */
75         @Override
76         public void init(MetaDataSource metadata, Library library) {
77                 http_client = HTTPClient.getNewHttpClient(library);
78         }
79
80         /**
81          * Perform a HTTP GET request to a given URL
82          * 
83          * @param url
84          *            URL to fetch
85          * @param encoding
86          *            Expected encoding of the response body
87          * @param ignore_errors
88          *            If true, status codes above 400 do not raise an exception
89          * @param cookieStore
90          *            If set, the given cookieStore is used instead of the built-in
91          *            one.
92          * @return Answer content
93          * @throws NotReachableException
94          *             Thrown when server returns a HTTP status code greater or
95          *             equal than 400.
96          */
97         public String httpGet(String url, String encoding, boolean ignore_errors,
98                         CookieStore cookieStore) throws ClientProtocolException,
99                         IOException {
100
101 //              HttpGet httpget = new HttpGet(cleanUrl(url));
102                 HttpGet httpget = new HttpGet(url);
103                 httpget.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.0; rv:32.0) Gecko/20100101 Firefox/32.0");
104                 HttpResponse response;
105
106                 try {
107                         if (cookieStore != null) {
108                                 // Create local HTTP context
109                                 HttpContext localContext = new BasicHttpContext();
110                                 // Bind custom cookie store to the local context
111                                 localContext.setAttribute(ClientContext.COOKIE_STORE,
112                                                 cookieStore);
113
114                                 response = http_client.execute(httpget, localContext);
115                         } else {
116                                 response = http_client.execute(httpget);
117                         }
118                 } catch (ConnectTimeoutException e) {
119                         e.printStackTrace();
120                         throw new NotReachableException();
121                 } catch (UnknownHostException e) {
122                         e.printStackTrace();
123                         throw new NotReachableException();
124                 } catch (IllegalStateException e) {
125                         e.printStackTrace();
126                         throw new NotReachableException();
127                 } catch (NoHttpResponseException e) {
128                         e.printStackTrace();
129                         throw new NotReachableException();
130                 } catch (MalformedChunkCodingException e) {
131                         e.printStackTrace();
132                         throw new NotReachableException();
133                 } catch (javax.net.ssl.SSLPeerUnverifiedException e) {
134                         // TODO: Handly this well
135                         throw e;
136                 } catch (javax.net.ssl.SSLException e) {
137                         // TODO: Handly this well
138                         // Can be "Not trusted server certificate" or can be a
139                         // aborted/interrupted handshake/connection
140                         if (e.getMessage().contains("timed out")
141                                         || e.getMessage().contains("reset by")) {
142                                 e.printStackTrace();
143                                 throw new NotReachableException();
144                         } else {
145                                 throw e;
146                         }
147                 } catch (InterruptedIOException e) {
148                         e.printStackTrace();
149                         throw new NotReachableException();
150                 } catch (IOException e) {
151                         if (e.getMessage() != null
152                                         && e.getMessage().contains("Request aborted")) {
153                                 e.printStackTrace();
154                                 throw new NotReachableException();
155                         } else {
156                                 throw e;
157                         }
158                 }
159
160                 if (!ignore_errors && response.getStatusLine().getStatusCode() >= 400) {
161                         throw new NotReachableException();
162                 }
163                 String html = convertStreamToString(response.getEntity().getContent(),
164                                 encoding);
165                 response.getEntity().consumeContent();
166                 return html;
167         }
168
169         public String httpGet(String url, String encoding, boolean ignore_errors)
170                         throws ClientProtocolException, IOException {
171                 return httpGet(url, encoding, ignore_errors, null);
172         }
173
174         public String httpGet(String url, String encoding)
175                         throws ClientProtocolException, IOException {
176                 return httpGet(url, encoding, false, null);
177         }
178
179         @Deprecated
180         public String httpGet(String url) throws ClientProtocolException,
181                         IOException {
182                 return httpGet(url, getDefaultEncoding(), false, null);
183         }
184
185         public static String cleanUrl(String myURL) {
186                 String[] parts = myURL.split("\\?");
187                 String url = parts[0];
188                 try {
189                         if (parts.length > 1) {
190                                 url += "?";
191                                 List<NameValuePair> params = new ArrayList<NameValuePair>();
192                                 String[] pairs = parts[1].split("&");
193                                 for (String pair : pairs) {
194                                         String[] kv = pair.split("=");
195                                         if (kv.length > 1)
196                                                 params.add(new BasicNameValuePair(URLDecoder.decode(
197                                                                 kv[0], "UTF-8"), URLDecoder.decode(kv[1],
198                                                                 "UTF-8")));
199                                         else
200                                                 params.add(new BasicNameValuePair(URLDecoder.decode(
201                                                                 kv[0], "UTF-8"), ""));
202                                 }
203                                 url += URLEncodedUtils.format(params, "UTF-8");
204                         }
205                         return url;
206                 } catch (UnsupportedEncodingException e) {
207                         e.printStackTrace();
208                         return myURL;
209                 }
210         }
211
212         public void downloadCover(CoverHolder item) {
213                 if (item.getCover() == null)
214                         return;
215                 HttpGet httpget = new HttpGet(cleanUrl(item.getCover()));
216                 HttpResponse response;
217
218                 try {
219                         response = http_client.execute(httpget);
220
221                         if (response.getStatusLine().getStatusCode() >= 400) {
222                                 return;
223                         }
224                         HttpEntity entity = response.getEntity();
225                         byte[] bytes = EntityUtils.toByteArray(entity);
226
227                         Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0,
228                                         bytes.length);
229                         item.setCoverBitmap(bitmap);
230
231                 } catch (IOException e) {
232                         e.printStackTrace();
233                         return;
234                 }
235         }
236
237         /**
238          * Perform a HTTP POST request to a given URL
239          * 
240          * @param url
241          *            URL to fetch
242          * @param data
243          *            POST data to send
244          * @param encoding
245          *            Expected encoding of the response body
246          * @param ignore_errors
247          *            If true, status codes above 400 do not raise an exception
248          * @param cookieStore
249          *            If set, the given cookieStore is used instead of the built-in
250          *            one.
251          * @return Answer content
252          * @throws NotReachableException
253          *             Thrown when server returns a HTTP status code greater or
254          *             equal than 400.
255          */
256         public String httpPost(String url, UrlEncodedFormEntity data,
257                         String encoding, boolean ignore_errors, CookieStore cookieStore)
258                         throws ClientProtocolException, IOException {
259                 HttpPost httppost = new HttpPost(cleanUrl(url));
260                 httppost.setEntity(data);
261
262                 HttpResponse response = null;
263                 try {
264                         if (cookieStore != null) {
265                                 // Create local HTTP context
266                                 HttpContext localContext = new BasicHttpContext();
267                                 // Bind custom cookie store to the local context
268                                 localContext.setAttribute(ClientContext.COOKIE_STORE,
269                                                 cookieStore);
270
271                                 response = http_client.execute(httppost, localContext);
272                         } else {
273                                 response = http_client.execute(httppost);
274                         }
275                 } catch (ConnectTimeoutException e) {
276                         e.printStackTrace();
277                         throw new NotReachableException();
278                 } catch (IllegalStateException e) {
279                         e.printStackTrace();
280                         throw new NotReachableException();
281                 } catch (UnknownHostException e) {
282                         e.printStackTrace();
283                         throw new NotReachableException();
284                 } catch (NoHttpResponseException e) {
285                         e.printStackTrace();
286                         throw new NotReachableException();
287                 } catch (MalformedChunkCodingException e) {
288                         e.printStackTrace();
289                         throw new NotReachableException();
290                 } catch (javax.net.ssl.SSLPeerUnverifiedException e) {
291                         // TODO: Handle this well
292                         if (e.getMessage().contains("timed out")
293                                         || e.getMessage().contains("reset by")) {
294                                 e.printStackTrace();
295                                 throw new NotReachableException();
296                         } else {
297                                 throw e;
298                         }
299                 } catch (javax.net.ssl.SSLException e) {
300                         // TODO: Handle this well
301                         // Can be "Not trusted server certificate" or can be a
302                         // aborted/interrupted handshake/connection
303                         throw e;
304                 } catch (InterruptedIOException e) {
305                         e.printStackTrace();
306                         throw new NotReachableException();
307                 } catch (IOException e) {
308                         if (e.getMessage() != null
309                                         && e.getMessage().contains("Request aborted")) {
310                                 e.printStackTrace();
311                                 throw new NotReachableException();
312                         } else {
313                                 throw e;
314                         }
315                 }
316
317                 if (!ignore_errors && response.getStatusLine().getStatusCode() >= 400) {
318                         throw new NotReachableException();
319                 }
320                 String html = convertStreamToString(response.getEntity().getContent(),
321                                 encoding);
322                 response.getEntity().consumeContent();
323                 return html;
324         }
325
326         public String httpPost(String url, UrlEncodedFormEntity data,
327                         String encoding, boolean ignore_errors)
328                         throws ClientProtocolException, IOException {
329                 return httpPost(url, data, encoding, ignore_errors, null);
330         }
331
332         public String httpPost(String url, UrlEncodedFormEntity data,
333                         String encoding) throws ClientProtocolException, IOException {
334                 return httpPost(url, data, encoding, false, null);
335         }
336
337         @Deprecated
338         public String httpPost(String url, UrlEncodedFormEntity data)
339                         throws ClientProtocolException, IOException {
340                 return httpPost(url, data, getDefaultEncoding(), false, null);
341         }
342
343         /**
344          * Reads content from an InputStream into a string
345          * 
346          * @param is
347          *            InputStream to read from
348          * @return String content of the InputStream
349          */
350         protected static String convertStreamToString(InputStream is,
351                         String encoding) throws IOException {
352                 BufferedReader reader;
353                 try {
354                         reader = new BufferedReader(new InputStreamReader(is, encoding));
355                 } catch (UnsupportedEncodingException e1) {
356                         reader = new BufferedReader(new InputStreamReader(is));
357                 }
358                 StringBuilder sb = new StringBuilder();
359
360                 String line = null;
361                 try {
362                         while ((line = reader.readLine()) != null) {
363                                 sb.append((line + "\n"));
364                         }
365                 } finally {
366                         try {
367                                 is.close();
368                         } catch (IOException e) {
369                                 e.printStackTrace();
370                         }
371                 }
372                 return sb.toString();
373         }
374
375         protected static String convertStreamToString(InputStream is)
376                         throws IOException {
377                 return convertStreamToString(is, "ISO-8859-1");
378         }
379
380         protected String getDefaultEncoding() {
381                 return "ISO-8859-1";
382         }
383
384         /*
385          * Gets all values of all query parameters in an URL.
386          */
387         public static Map<String, List<String>> getQueryParams(String url) {
388                 try {
389                         Map<String, List<String>> params = new HashMap<String, List<String>>();
390                         String[] urlParts = url.split("\\?");
391                         if (urlParts.length > 1) {
392                                 String query = urlParts[1];
393                                 for (String param : query.split("&")) {
394                                         String[] pair = param.split("=");
395                                         String key = URLDecoder.decode(pair[0], "UTF-8");
396                                         String value = "";
397                                         if (pair.length > 1) {
398                                                 value = URLDecoder.decode(pair[1], "UTF-8");
399                                         }
400
401                                         List<String> values = params.get(key);
402                                         if (values == null) {
403                                                 values = new ArrayList<String>();
404                                                 params.put(key, values);
405                                         }
406                                         values.add(value);
407                                 }
408                         }
409
410                         return params;
411                 } catch (UnsupportedEncodingException ex) {
412                         throw new AssertionError(ex);
413                 }
414         }
415
416         /*
417          * Gets the value for every query parameter in the URL. If a parameter name
418          * occurs twice or more, only the first occurance is interpreted by this
419          * method
420          */
421         public static Map<String, String> getQueryParamsFirst(String url) {
422                 try {
423                         Map<String, String> params = new HashMap<String, String>();
424                         String[] urlParts = url.split("\\?");
425                         if (urlParts.length > 1) {
426                                 String query = urlParts[1];
427                                 for (String param : query.split("&")) {
428                                         String[] pair = param.split("=");
429                                         String key = URLDecoder.decode(pair[0], "UTF-8");
430                                         String value = "";
431                                         if (pair.length > 1) {
432                                                 value = URLDecoder.decode(pair[1], "UTF-8");
433                                         }
434
435                                         String values = params.get(key);
436                                         if (values == null) {
437                                                 params.put(key, value);
438                                         }
439                                 }
440                         }
441
442                         return params;
443                 } catch (UnsupportedEncodingException ex) {
444                         throw new AssertionError(ex);
445                 }
446         }
447 }