All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tinymediamanager.jsonrpc.io.JsonApiRequest Maven / Gradle / Ivy

Go to download

This library is the result of freezy's Kodi JSON introspection, merged with dereulenspiegel's adoption without android, and patched to Kodi 16 Jarvis.

The newest version!
/*
 *      Copyright (C) 2005-2015 Team XBMC
 *      http://xbmc.org
 *
 *  This Program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This Program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with XBMC Remote; see the file license.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *  http://www.gnu.org/copyleft/gpl.html
 *
 */

package org.tinymediamanager.jsonrpc.io;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;

import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ObjectNode;
import org.codehaus.jackson.node.TextNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tinymediamanager.jsonrpc.config.HostConfig;

/**
 * Performs HTTP POST requests on the XBMC JSON API and handles the parsing from and to {@link ObjectNode}.
 * 

* Note: All in here is synchronous. * * @author Joel Stemmer * @author freezy */ public class JsonApiRequest { private static final Logger LOGGER = LoggerFactory.getLogger(JsonApiRequest.class); private static final String TAG = JsonApiRequest.class.getSimpleName(); private static final int REQUEST_TIMEOUT = 5000; // 5 sec private static final ObjectMapper OM = new ObjectMapper(); /** * Executes a POST request to the URL using the JSON Object as request body and returns a JSON Object if the response was successful. * * @param url * Complete URL with schema, host, port if not default and path. * @param entity * Object being serialized as message body * @return JSON Object of the JSON-RPC response. * @throws ApiException */ public static ObjectNode execute(HostConfig config, ObjectNode entity) throws ApiException { String response = postRequest(config, entity.toString()); LOGGER.debug("Response: {}", response); return parseResponse(response); } /** * Execute a POST request on URL using entity as request body. * * @param url * @param entity * @return The response as a string * @throws ApiException * @throws IOException */ private static String postRequest(HostConfig config, String entity) throws ApiException { try { URL url = new URL("http", config.getAddress(), config.getHttpPort(), "/jsonrpc"); final HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); // http basic authorization if (config.getUsername() != null && !config.getUsername().isEmpty() && config.getPassword() != null && !config.getPassword().isEmpty()) { final String token = Base64.encodeToString((config.getUsername() + ":" + config.getPassword()).getBytes(), false); conn.setRequestProperty("Authorization", "Basic " + token); } conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("User-Agent", buildUserAgent()); conn.setConnectTimeout(REQUEST_TIMEOUT); conn.setReadTimeout(REQUEST_TIMEOUT); conn.setDoOutput(true); LOGGER.debug("Request: {}", entity.toString()); try { OutputStreamWriter output = new OutputStreamWriter(conn.getOutputStream(), "UTF-8"); output.write(entity); output.close(); } catch (UnsupportedEncodingException e) { throw new ApiException(ApiException.UNSUPPORTED_ENCODING, "Unable to convert request to UTF-8", e); } StringBuilder response = new StringBuilder(); BufferedReader reader = null; final int code = conn.getResponseCode(); if (code == 200) { try { reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"), 8192); String line; while ((line = reader.readLine()) != null) { response.append(line); } } catch (UnsupportedEncodingException e) { throw new ApiException(ApiException.UNSUPPORTED_ENCODING, "Unable to convert HTTP response to UTF-8", e); } finally { if (reader != null) { reader.close(); } } return response.toString(); } else { switch (code) { case 400: throw new ApiException(ApiException.HTTP_BAD_REQUEST, "Server says \"400 Bad HTTP request\"."); case 401: throw new ApiException(ApiException.HTTP_UNAUTHORIZED, "Server says \"401 Unauthorized\"."); case 403: throw new ApiException(ApiException.HTTP_FORBIDDEN, "Server says \"403 Forbidden\"."); case 404: throw new ApiException(ApiException.HTTP_NOT_FOUND, "Server says \"404 Not Found\"."); default: if (code >= 100 && code < 200) { throw new ApiException(ApiException.HTTP_INFO, "Server returned informational code " + code + " instead of 200."); } else if (code >= 200 && code < 300) { throw new ApiException(ApiException.HTTP_SUCCESS, "Server returned success code " + code + " instead of 200."); } else if (code >= 300 && code < 400) { throw new ApiException(ApiException.HTTP_REDIRECTION, "Server returned redirection code " + code + " instead of 200."); } else if (code >= 400 && code < 500) { throw new ApiException(ApiException.HTTP_CLIENT_ERROR, "Server returned client error " + code + "."); } else if (code >= 500 && code < 600) { throw new ApiException(ApiException.HTTP_SERVER_ERROR, "Server returned server error " + code + "."); } else { throw new ApiException(ApiException.HTTP_UNKNOWN, "Server returned unspecified code " + code + "."); } } } } catch (MalformedURLException e) { throw new ApiException(ApiException.MALFORMED_URL, e.getMessage(), e); } catch (SocketTimeoutException e) { throw new ApiException(ApiException.IO_SOCKETTIMEOUT, e.getMessage(), e); } catch (ConnectException e) { throw new ApiException(ApiException.IO_EXCEPTION_WHILE_OPENING, e.getMessage(), e); } catch (IOException e) { throw new ApiException(ApiException.IO_EXCEPTION, e.getMessage(), e); } } /** * Parses the JSON response string and returns a {@link ObjectNode}. * * If the response is not valid JSON, contained an error message or did not include a result then a HandlerException is thrown. * * @param response * @return ObjectNode Root node of the server response, unserialized as ObjectNode. * @throws ApiException */ private static ObjectNode parseResponse(String response) throws ApiException { try { final ObjectNode node = (ObjectNode) OM.readTree(response.toString()); if (node.has("error")) { if (node.get("error").isTextual()) { final TextNode error = (TextNode) node.get("error"); throw new ApiException(ApiException.API_ERROR, "Error: " + error.getTextValue(), null); } else { final ObjectNode error = (ObjectNode) node.get("error"); throw new ApiException(ApiException.API_ERROR, "Error " + error.get("code").getIntValue() + ": " + error.get("message").getTextValue(), null); } } if (!node.has("result")) { throw new ApiException(ApiException.RESPONSE_ERROR, "Neither result nor error object found in response.", null); } if (node.get("result").isNull()) { return null; } return node; } catch (JsonProcessingException e) { throw new ApiException(ApiException.JSON_EXCEPTION, "Parse error: " + e.getMessage(), e); } catch (IOException e) { throw new ApiException(ApiException.JSON_EXCEPTION, "Parse error: " + e.getMessage(), e); } } /** * Build user agent used for the HTTP requests * * TODO: include version information * * @return String containing the user agent */ private static String buildUserAgent() { return "tinyMediaManager-jsonrpclib-kodi"; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy