Java tutorial
/* * Copyright 2014-2015 Ronald Hoffman. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.ScripterRon.BitcoinMonitor; import static org.ScripterRon.BitcoinMonitor.Main.log; import org.json.simple.JSONArray; import org.json.simple.parser.ContainerFactory; import org.json.simple.parser.JSONParser; import java.io.FilterOutputStream; import java.io.InputStreamReader; import java.io.IOException; import java.net.Authenticator; import java.net.PasswordAuthentication; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.atomic.AtomicLong; import java.util.List; import java.util.Map; /** * Make API requests to the Bitcoin node and return the response */ public class Request { /** Response container factory */ private static final ContainerFactory containerFactory = new ResponseFactory(); /** Connect timeout (milliseconds) */ private static final int nodeConnectTimeout = 5000; /** Read timeout (milliseconds) */ private static final int nodeReadTimeout = 30000; /** Request identifier */ private static final AtomicLong requestId = new AtomicLong(0); /** Set up our default authenticator */ static { Authenticator.setDefault(new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(Main.rpcUser, Main.rpcPassword.toCharArray()); } }); } /** * Get the block for the specified block hash * * @param blockHash Block hash * @return Block * @throws IOException Unable to issue Bitcoin RPC request * @throws ParseException Unable to parse the Bitcoin RPC response */ public static Response getBlock(String blockHash) throws IOException, ParseException { Response response = issueRequest("getblock", String.format("[\"%s\"]", blockHash)); Object result = response.get("result"); if (result == null || !(result instanceof Response)) { log.error("'getblock' result is not a JSONObject"); throw new ParseException("'getblock' result is not a JSONObject"); } return (Response) result; } /** * Get the block hash for the specified block chain height * * @param height Block chain height * @return Block hash * @throws IOException Unable to issue Bitcoin RPC request * @throws ParseException Unable to parse the Bitcoin RPC response */ public static String getBlockHash(int height) throws IOException, ParseException { Response response = issueRequest("getblockhash", String.format("[%d]", height)); Object result = response.get("result"); if (result == null || !(result instanceof String)) { log.error("'getblockhash' result is not a String"); throw new ParseException("'getblockhash' result is not a String"); } return (String) result; } /** * Get the server log messages using the getlog method * * @return Log message list * @throws IOException Unable to issue Bitcoin RPC request * @throws ParseException Unable to parse the Bitcoin RPC response */ public static List getLog() throws IOException, ParseException { Response response = issueRequest("getlog", null); Object result = response.get("result"); if (result == null || !(result instanceof JSONArray)) { log.error("'getlog' result is not a JSONArray"); throw new ParseException("'getlog' result is not a JSONArray"); } return (List) result; } /** * Get node information using the getinfo method * * @return Node information * @throws IOException Unable to issue Bitcoin RPC request * @throws ParseException Unable to parse the Bitcoin RPC response */ public static Response getNodeInfo() throws IOException, ParseException { Response response = issueRequest("getinfo", null); Object result = response.get("result"); if (result == null || !(result instanceof Response)) { log.error("'getinfo' result is not a JSONObject"); throw new ParseException("'getinfo' result is not a JSONObject"); } return (Response) result; } /** * Get peer information using the getpeerinfo method * * @return Peer information * @throws IOException Unable to issue Bitcoin RPC request * @throws ParseException Unable to parse the Bitcoin RPC response */ public static List getPeerInfo() throws IOException, ParseException { Response response = issueRequest("getpeerinfo", null); Object result = response.get("result"); if (result == null || !(result instanceof JSONArray)) { log.error("'getperrinfo' result is not a JSONArray"); throw new ParseException("'getperrinfo' result is not a JSONArray"); } return (List) result; } /** * Get the server stack traces using the getstacktraces method * * @return Server stack traces * @throws IOException Unable to issue Bitcoin RPC request * @throws ParseException Unable to parse the Bitcoin RPC response */ public static StackTraces getStackTraces() throws IOException, ParseException { Response response = issueRequest("getstacktraces", null); Object result = response.get("result"); if (result == null || !(result instanceof Response)) { log.error("'getstacktraces' result is not a JSONObject"); throw new ParseException("'getstacktraces' result is not a JSONObject"); } return new StackTraces((Response) result); } /** * Issue the Bitcoin RPC request and return the parsed JSON response * * @param requestType Request type * @param requestParams Request parameters in JSON format or null if no parameters * @return Parsed JSON response * @throws IOException Unable to issue Bitcoin RPC request * @throws ParseException Unable to parse the Bitcoin RPC response */ private static Response issueRequest(String requestType, String requestParams) throws IOException, ParseException { long id = requestId.incrementAndGet(); Response response = null; try { URL url = new URL(String.format("http://%s:%d/", Main.rpcHost, Main.rpcPort)); String request; if (requestParams != null) { request = String.format("{\"jsonrpc\": \"2.0\", \"method\": \"%s\", \"params\": %s, \"id\": %d}", requestType, requestParams, id); } else { request = String.format("{\"jsonrpc\": \"2.0\", \"method\": \"%s\", \"id\": %d}", requestType, id); } log.debug(String.format("Issue HTTP request to %s:%d: %s", Main.rpcHost, Main.rpcPort, request)); byte[] requestBytes = request.getBytes("UTF-8"); // // Issue the request // HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/json-rpc"); conn.setRequestProperty("Cache-Control", "no-cache, no-store"); conn.setRequestProperty("Content-Length", String.format("%d", requestBytes.length)); conn.setRequestProperty("Accept", "application/json-rpc"); conn.setDoInput(true); conn.setDoOutput(true); conn.setUseCaches(false); conn.setConnectTimeout(nodeConnectTimeout); conn.setReadTimeout(nodeReadTimeout); conn.connect(); try (FilterOutputStream out = new FilterOutputStream(conn.getOutputStream())) { out.write(requestBytes); out.flush(); int code = conn.getResponseCode(); if (code != HttpURLConnection.HTTP_OK) { String errorText = String.format("Response code %d for %s request\n %s", code, requestType, conn.getResponseMessage()); log.error(errorText); throw new IOException(errorText); } } // // Parse the response // try (InputStreamReader in = new InputStreamReader(conn.getInputStream(), "UTF-8")) { JSONParser parser = new JSONParser(); response = (Response) parser.parse(in, containerFactory); Response errorResponse = (Response) response.getObject("error"); if (errorResponse != null) { String errorText = String.format("Error %d returned for %s request\n %s", errorResponse.getInt("code"), requestType, errorResponse.getString("message")); log.error(errorText); throw new IOException(errorText); } } if (log.isDebugEnabled()) log.debug(String.format("Request complete\n%s", Utils.formatJSON(response))); } catch (MalformedURLException exc) { throw new IOException("Malformed Bitcoin RPC URL", exc); } catch (org.json.simple.parser.ParseException exc) { String errorText = String.format("JSON parse exception for %s request: Position %d, Code %d", requestType, exc.getPosition(), exc.getErrorType()); log.error(errorText); throw new ParseException(errorText, exc.getPosition(), exc.getErrorType()); } catch (IOException exc) { String errorText = String.format("I/O error on %s request", requestType); log.error(errorText, exc); throw new IOException(errorText); } return response; } /** * JSON container factory * * We will create Response for an object and JSONArray<Object> for an array */ private static class ResponseFactory implements ContainerFactory { /** * Create an object container * * @return PeerResponse */ @Override public Map createObjectContainer() { return new Response(); } /** * Create an array container * * @return JSONArray */ @Override public List<Object> creatArrayContainer() { return new JSONArray(); } } }