/* * Copyright (c) 2009-2010, Metaweb Technologies, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY METAWEB TECHNOLOGIES AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL METAWEB * TECHNOLOGIES OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ package com.freebase.api; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringWriter; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.utils.URLEncodedUtils; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.json.simple.parser.ParseException; import com.freebase.json.JSON; abstract class JSONTransport { private static final int URL_SIZE_LIMIT = 2047; private static final int GET = 0; private static final int POST = 1; // ------------------------------------------------------------------------------ protected abstract String getURL(String path); protected abstract void sign(HttpRequestBase method); // ------------------------------------------------------------------------------ protected JSON get(String uri) { return get(uri, null, false); } protected JSON get(URI uri) { return get(uri, null, false); } protected JSON get(String uri, Map<String,String> headers) { return get(uri, headers, false); } protected JSON get(String uri, Map<String,String> headers, boolean sign) { try { return get(new URI(uri), headers, sign); } catch (URISyntaxException e) { throw new FreebaseException(e); } } protected JSON get(URI uri, Map<String,String> headers, boolean sign) { if (headers == null) headers = new HashMap<String,String>(); return check_result(urlfetch(uri,GET,headers,null,sign)); } protected JSON post(String uri, CharSequence content) { return post(uri, null, content, false); } protected JSON post(String uri, Map<String,String> headers, CharSequence content) { return post(uri, headers, content, false); } protected JSON post(String uri, Map<String,String> headers, CharSequence content, boolean sign) { try { return post(new URI(uri), headers, content, sign); } catch (URISyntaxException e) { throw new FreebaseException(e); } } protected JSON post(URI uri, CharSequence content) { return post(uri, null, content, false); } protected JSON post(URI uri, Map<String,String> headers, CharSequence content) { return post(uri, headers, content, false); } protected JSON post(URI uri, Map<String,String> headers, CharSequence content, boolean sign) { if (headers == null) headers = new HashMap<String,String>(); if (!headers.containsKey("content-type")) { headers.put("content-type","application/x-www-form-urlencoded"); } headers.put("X-Requested-With","1"); return check_result(urlfetch(uri,POST,headers,content,sign)); } protected JSON post(String path, List<NameValuePair> params) { return post(path, params, false); } protected JSON post(String path, List<NameValuePair> params, boolean sign) { String content = URLEncodedUtils.format(params, "UTF-8"); String url = getURL(path); return post(url, null, content, sign); } private JSON urlfetch(URI uri, int protocol, Map<String,String> headers, CharSequence content, boolean sign) { JSON result = null; try { HttpClient httpclient = new DefaultHttpClient(); HttpRequestBase method = null; if (protocol == GET) { method = new HttpGet(uri); } else { HttpPost httppost = new HttpPost(uri); httppost.setEntity(new StringEntity(content.toString())); method = httppost; } for (Map.Entry<String,String> e : headers.entrySet()) { method.setHeader(e.getKey(), e.getValue()); } if (sign) { sign(method); } HttpResponse response = httpclient.execute(method); HttpEntity entity = response.getEntity(); if (entity != null) { result = JSON.parse(new InputStreamReader(entity.getContent(),"UTF-8")); } else { result = JSON.o(); } } catch (ClientProtocolException e) { throw new FreebaseException(e); } catch (IOException e) { throw new FreebaseException(e); } catch (IllegalStateException e) { throw new FreebaseException(e); } catch (ParseException e) { throw new FreebaseException(e); } catch (ClassCastException e) { throw new FreebaseException(e); } return check_result(result); } protected JSON invoke(String path, List<NameValuePair> params) { return invoke(path, params, false); } protected JSON invoke(String path, List<NameValuePair> params, boolean sign) { String content = URLEncodedUtils.format(params, "UTF-8"); String url = getURL(path); if (url.length() + content.length() < URL_SIZE_LIMIT) { return get(url + "?" + content, null, sign); } else { return post(url, null, content, sign); } } @SuppressWarnings("unchecked") protected static String join(JSON s, String delimiter) { if (s.array().isEmpty()) return ""; Iterator<JSON> iter = s.array().iterator(); StringBuffer buffer = new StringBuffer(iter.next().string()); while (iter.hasNext()) { buffer.append(delimiter).append(iter.next()); } return buffer.toString(); } private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; protected static String stringify(Reader input) throws IOException { StringWriter output = new StringWriter(); char[] buffer = new char[DEFAULT_BUFFER_SIZE]; long count = 0; int n = 0; while (-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); count += n; } return output.toString(); } @SuppressWarnings("unchecked") protected static List<NameValuePair> transform_params(JSON params) { List<NameValuePair> qparams = new ArrayList<NameValuePair>(); if (params != null) { for (Object entry : params.object().entrySet()) { Map.Entry<String,JSON> e = (Map.Entry<String,JSON>) entry; qparams.add(new BasicNameValuePair(e.getKey(),e.getValue().value().toString())); } } return qparams; } protected static JSON jsonize(Object json) { if (json instanceof String) { try { json = JSON.parse((String) json); } catch (ParseException e) { throw new FreebaseException("Error during parsing, make sure it's a valid JSON object: " + e.getMessage()); } } if (json instanceof JSON) { JSON j = (JSON) json; if (!j.isContainer()) { throw new FreebaseException("Top level JSON object an object or an array"); } } return (JSON) json; } @SuppressWarnings("unchecked") private JSON check_result(JSON result) { if (result.has("status")) { String status = result.get("status").string(); String code = result.get("code").string(); if (!"200 OK".equals(status) || !"/api/status/ok".equals(code)) { String message = code; if (!"200 OK".equals(status)) { message = "HTTP error: " + status; } else { JSON firstMessage = result.get("messages").get(0); if (firstMessage.has("message")) { message = code + ": " + firstMessage.get("message").string(); } } throw new FreebaseException(message, result); } } else { for (Object e : result.object().entrySet()) { Map.Entry<String, JSON> entry = (Map.Entry<String, JSON>) e; check_result(entry.getValue()); } } return result; } }