Back to project page bitpay-android-sdk.
The source code is released under:
MIT License
If you think the Android project bitpay-android-sdk listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package com.bitpay.androidsdk.controller; //from w ww . ja va 2 s . c o m import com.bitpay.androidsdk.model.Invoice; import com.bitpay.androidsdk.model.Rate; import com.bitpay.androidsdk.model.Rates; import com.bitpay.androidsdk.model.Token; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.bitcoin.core.ECKey; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.ParseException; 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.entity.ByteArrayEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.Arrays; import java.util.Date; import java.util.Hashtable; import java.util.List; public class BitPay { private static final String BITPAY_API_VERSION = "2.0.0"; private static final String BITPAY_PLUGIN_INFO = "BitPay Java Client " + BITPAY_API_VERSION; private static final String BITPAY_URL = "https://bitpay.com/"; public static final String FACADE_PAYROLL = "payroll"; public static final String FACADE_POS = "pos"; public static final String FACADE_MERCHANT = "merchant"; public static final String FACADE_USER = "user"; private HttpClient _httpClient = null; private String _baseUrl = BITPAY_URL; public ECKey _ecKey = null; private String _identity = ""; private long _nonce = new Date().getTime(); private boolean _disableNonce = false; private String _clientName = ""; protected Hashtable<String, String> _tokenCache; // {facade, token} /** * Constructor for use if the keys and SIN are managed by this library. * @param clientName - The label for this client. * @param envUrl - The target server URL. * @throws BitPayException */ public BitPay(String clientName, String envUrl) throws BitPayException { if (clientName.equals(BITPAY_PLUGIN_INFO)) { try { clientName += " on " + java.net.InetAddress.getLocalHost(); } catch (UnknownHostException e) { clientName += " on unknown host"; } } _clientName = clientName; _baseUrl = envUrl; _httpClient = new DefaultHttpClient(); try { this.initKeys(); } catch (IOException e) { throw new BitPayException("Error: failed to intialize public/private key pair\n" + e.getMessage()); } this.deriveIdentity(); this.tryGetAccessTokens(); } public BitPay(String clientName) throws BitPayException { this(clientName, BITPAY_URL); } public BitPay() throws BitPayException { this(BITPAY_PLUGIN_INFO, BITPAY_URL); } /** * Constructor for use if the keys and SIN were derived external to this library. * @param ecKey - An elliptical curve key. * @param clientName - The label for this client. * @param envUrl - The target server URL. * @throws BitPayException */ public BitPay(ECKey ecKey, String clientName, String envUrl) throws BitPayException { _ecKey = ecKey; this.deriveIdentity(); _baseUrl = envUrl; _httpClient = new DefaultHttpClient(); this.tryGetAccessTokens(); } public String getIdentity() { return _identity; } public boolean getDisableNonce() { return _disableNonce; } public void setDisableNonce(boolean value) { _disableNonce = value; } public void authorizeClient(String pairingCode) throws BitPayException { Token token = new Token(); token.setId(_identity); token.setGuid(this.getGuid()); token.setNonce(getNextNonce()); token.setPairingCode(pairingCode); token.setLabel(_clientName); ObjectMapper mapper = new ObjectMapper(); String json; try { json = mapper.writeValueAsString(token); } catch (JsonProcessingException e) { throw new BitPayException("Error - failed to serialize Token object : " + e.getMessage()); } HttpResponse response = this.post("tokens", json); List<Token> tokens; try { tokens = Arrays.asList(mapper.readValue(this.responseToJsonString(response), TokenWrapper.class).data); } catch (JsonProcessingException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Tokens) : " + e.getMessage()); } catch (IOException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Tokens) : " + e.getMessage()); } for (Token t : tokens) { _tokenCache.put(t.getFacade(), t.getValue()); } } public List<Token> createToken(String facade) throws BitPayException { Token token = new Token(); token.setId(_identity); token.setGuid(this.getGuid()); token.setNonce(getNextNonce()); token.setLabel(_clientName); token.setFacade(facade); ObjectMapper mapper = new ObjectMapper(); String json; try { json = mapper.writeValueAsString(token); } catch (JsonProcessingException e) { throw new BitPayException("Error - failed to serialize Token object : " + e.getMessage()); } HttpResponse response = this.post("tokens", json); List<Token> tokens; try { tokens = Arrays.asList(mapper.readValue(this.responseToJsonString(response), TokenWrapper.class).data); } catch (JsonProcessingException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Tokens) : " + e.getMessage()); } catch (IOException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Tokens) : " + e.getMessage()); } for (Token t : tokens) { _tokenCache.put(t.getFacade(), t.getValue()); } return tokens; } public boolean clientIsAuthorized(String facade) { return _tokenCache.containsKey(facade); } public Invoice createInvoice(Invoice invoice, String facade) throws BitPayException { invoice.setToken(this.getAccessToken(facade)); invoice.setGuid(this.getGuid()); invoice.setNonce(this.getNextNonce()); ObjectMapper mapper = new ObjectMapper(); String json; try { json = mapper.writeValueAsString(invoice); } catch (JsonProcessingException e) { throw new BitPayException("Error - failed to serialize Invoice object : " + e.getMessage()); } HttpResponse response = this.postWithSignature("invoices", json); try { invoice = mapper.readValue(this.responseToJsonString(response), InvoiceWrapper.class).data; } catch (JsonProcessingException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Invoice) : " + e.getMessage()); } catch (IOException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Invoice) : " + e.getMessage()); } return invoice; } public Invoice createInvoice(Invoice invoice) throws BitPayException { return this.createInvoice(invoice, FACADE_POS); } public Invoice getInvoice(String invoiceId) throws BitPayException { HttpResponse response = this.get("invoices/" + invoiceId); Invoice i; try { i = new ObjectMapper().readValue(this.responseToJsonString(response), InvoiceWrapper.class).data; } catch (JsonProcessingException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Invoice) : " + e.getMessage()); } catch (IOException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Invoice) : " + e.getMessage()); } return i; } public List<Invoice> getInvoices(String dateStart, String dateEnd) throws BitPayException { Hashtable<String, String> parameters = this.getParams(); parameters.put("token", this.getAccessToken(FACADE_MERCHANT)); parameters.put("dateStart", dateStart); parameters.put("dateEnd", dateEnd); HttpResponse response = this.get("invoices", parameters); List<Invoice> invoices; try { invoices = new ObjectMapper().readValue(this.responseToJsonString(response), InvoicesWrapper.class).data; } catch (JsonProcessingException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Invoices) : " + e.getMessage()); } catch (IOException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Invoices) : " + e.getMessage()); } return invoices; } public Rates getRates() throws BitPayException { HttpResponse response = this.get("rates"); List<Rate> rates; try { rates = Arrays.asList(new ObjectMapper().readValue(this.responseToJsonString(response), RatesWrapper.class).data); } catch (JsonProcessingException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Rates) : " + e.getMessage()); } catch (IOException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Rates) : " + e.getMessage()); } return new Rates(rates); } private void initKeys() throws IOException { _ecKey = KeyUtils.createEcKey(); } private void deriveIdentity() throws IllegalArgumentException { // Identity in this implementation is defined to be the SIN. _identity = KeyUtils.deriveSIN(_ecKey); } private long getNextNonce() { if (!getDisableNonce()) { _nonce++; } else { _nonce = 0; // Nonce must be 0 when it has been disabled (0 value prevents serialization) } return _nonce; } private Hashtable<String, String> responseToTokenCache(HttpResponse response) throws BitPayException { // The response is expected to be an array of key/value pairs (facade name = token). String json = this.responseToJsonString(response); _tokenCache = new Hashtable<String, String>(); try { for (Hashtable<String, String> entry1 : new ObjectMapper().readValue(json, TokenCacheWrapper.class).data) { _tokenCache.putAll(entry1); } } catch (JsonProcessingException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Token array) : " + e.getMessage()); } catch (IOException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Token array) : " + e.getMessage()); } return _tokenCache; } private void clearAccessTokenCache() { _tokenCache = new Hashtable<String, String>(); } private boolean tryGetAccessTokens() throws BitPayException { // Attempt to get access tokens for this client identity. try { // Success if at least one access token was returned. return this.getAccessTokens() > 0; } catch (BitPayException ex) { // If the error states that the identity is invalid then this client has not been // registered with the BitPay account. if (ex.getMessage().contains("Unauthorized sin")) { this.clearAccessTokenCache(); return false; } else { // Propagate all other errors. throw ex; } } } public List<Token> getTokens() throws BitPayException { HttpResponse response = this.get("tokens", getParams()); try { return Arrays.asList(new ObjectMapper().readValue(this.responseToJsonString(response), TokenWrapper.class).data); } catch (JsonProcessingException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Invoice) : " + e.getMessage()); } catch (IOException e) { throw new BitPayException("Error - failed to deserialize BitPay server response (Invoice) : " + e.getMessage()); } } protected int getAccessTokens() throws BitPayException { this.clearAccessTokenCache(); Hashtable<String, String> parameters = this.getParams(); HttpResponse response = this.get("tokens", parameters); _tokenCache = responseToTokenCache(response); return _tokenCache.size(); } private String getAccessToken(String facade) throws BitPayException { if (!_tokenCache.containsKey(facade)) { throw new BitPayException("Error: You do not have access to facade: " + facade); } return _tokenCache.get(facade); } private Hashtable<String, String> getParams() { Hashtable<String, String> params = new Hashtable<String, String>(); params.put("nonce", getNextNonce() + ""); return params; } private HttpResponse get(String uri, Hashtable<String, String> parameters) throws BitPayException { try { String fullURL = _baseUrl + uri; HttpGet get = new HttpGet(fullURL); if (parameters != null) { fullURL += "?"; for (String key : parameters.keySet()) { fullURL += key + "=" + parameters.get(key) + "&"; } fullURL = fullURL.substring(0,fullURL.length() - 1); get.setURI(new URI(fullURL)); String signature = KeyUtils.sign(_ecKey, fullURL); get.addHeader("x-bitpay-plugin-info", BITPAY_PLUGIN_INFO); get.addHeader("x-accept-version", BITPAY_API_VERSION); get.addHeader("x-signature", signature); get.addHeader("x-identity", KeyUtils.bytesToHex(_ecKey.getPubKey())); } return _httpClient.execute(get); } catch (URISyntaxException e) { throw new BitPayException("Error: GET failed\n" + e.getMessage()); } catch (ClientProtocolException e) { throw new BitPayException("Error: GET failed\n" + e.getMessage()); } catch (IOException e) { throw new BitPayException("Error: GET failed\n" + e.getMessage()); } } private HttpResponse get(String uri) throws BitPayException { return this.get(uri, null); } private HttpResponse post(String uri, String json, boolean signatureRequired) throws BitPayException { try { HttpPost post = new HttpPost(_baseUrl + uri); post.setEntity(new ByteArrayEntity(json.toString().getBytes("UTF8"))); if (signatureRequired) { String signature = KeyUtils.sign(_ecKey, _baseUrl + uri + json); post.addHeader("x-signature", signature); post.addHeader("x-identity", KeyUtils.bytesToHex(_ecKey.getPubKey())); } post.addHeader("x-accept-version", BITPAY_API_VERSION); post.addHeader("x-bitpay-plugin-info", BITPAY_PLUGIN_INFO); post.addHeader("Content-Type","application/json"); return _httpClient.execute(post); } catch (UnsupportedEncodingException e) { throw new BitPayException("Error: POST failed\n" + e.getMessage()); } catch (ClientProtocolException e) { throw new BitPayException("Error: POST failed\n" + e.getMessage()); } catch (IOException e) { throw new BitPayException("Error: POST failed\n" + e.getMessage()); } } private HttpResponse post(String uri, String json) throws BitPayException { return this.post(uri, json, false); } private HttpResponse postWithSignature(String uri, String json) throws BitPayException { return this.post(uri, json, true); } private String responseToJsonString(HttpResponse response) throws BitPayException { if (response == null) { throw new BitPayException("Error: HTTP response is null"); } try { // Get the JSON string from the response. HttpEntity entity = response.getEntity(); String jsonString; jsonString = EntityUtils.toString(entity, "UTF-8"); ObjectMapper mapper = new ObjectMapper(); JsonNode rootNode = mapper.readTree(jsonString); JsonNode node = rootNode.get("error"); if (node != null) { throw new BitPayException("Error: " + jsonString); } node = rootNode.get("errors"); if (node != null) { String message = "Multiple errors:"; if (node.isArray()) { for (final JsonNode errorNode : node) { message += "\n" + errorNode.asText(); } throw new BitPayException(message); } } rootNode.get("data"); return jsonString; } catch (ParseException e) { throw new BitPayException("Error - failed to retrieve HTTP response body : " + e.getMessage()); } catch (JsonMappingException e) { throw new BitPayException("Error - failed to parse json response to map : " + e.getMessage()); } catch (IOException e) { throw new BitPayException("Error - failed to retrieve HTTP response body : " + e.getMessage()); } } private String getGuid() { int Min = 0; int Max = 99999999; return Min + (int)(Math.random() * ((Max - Min) + 1)) + ""; } public Token newToken(String facade) { Token token = new Token(); token.setId(_identity); token.setGuid(this.getGuid()); token.setNonce(getNextNonce()); token.setLabel(_clientName); token.setFacade(facade); return token; } public static class Wrapper<D> { public Wrapper() { } @JsonProperty("data") public D data; @JsonProperty("facade") public String facade; } public static class TokenWrapper extends Wrapper<Token[]> { public TokenWrapper() { super(); } } public static class InvoiceWrapper extends Wrapper<Invoice> { public InvoiceWrapper() { super(); } } public static class InvoicesWrapper extends Wrapper<List<Invoice>> { public InvoicesWrapper() { super(); } } public static class TokenCacheWrapper extends Wrapper<Hashtable<String, String>[]> { public TokenCacheWrapper() { super(); } } public static class RatesWrapper extends Wrapper<Rate[]> { public RatesWrapper() { super(); } } }