JCoinbaseClient.java
package com.github.badpop.jcoinbase.client;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.github.badpop.jcoinbase.client.service.auth.AuthenticationService;
import com.github.badpop.jcoinbase.client.service.data.CoinbaseDataService;
import com.github.badpop.jcoinbase.client.service.data.DataService;
import com.github.badpop.jcoinbase.client.service.user.CoinbaseUserService;
import com.github.badpop.jcoinbase.client.service.user.UserService;
import com.github.badpop.jcoinbase.exception.JCoinbaseException;
import com.github.badpop.jcoinbase.service.ErrorManagerService;
import io.vavr.jackson.datatype.VavrModule;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.experimental.FieldDefaults;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import java.net.http.HttpClient;
import java.time.Duration;
import java.time.ZoneId;
import java.util.TimeZone;
import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS;
import static java.net.http.HttpClient.Redirect.NEVER;
import static java.time.temporal.ChronoUnit.SECONDS;
import static lombok.AccessLevel.PRIVATE;
import static lombok.AccessLevel.PROTECTED;
/**
* The JCoinbaseClient class is the main class of JCoinbase. JCoinbaseClient allows you make
* requests to the Coinbase API in a fluent and simple way using it's api.
*
* <p>To build a new JCoinbaseClient object you should use the {@link JCoinbaseClientFactory}
*
* <p>Make request to Coinbase api using these methods :
*
* <ul>
* <li>{@link #data()} to access public data
* <li>{@link #user()} to access users data
* </ul>
*/
@Slf4j
@FieldDefaults(level = PRIVATE)
@NoArgsConstructor(access = PROTECTED)
public class JCoinbaseClient {
@Getter HttpClient httpClient;
@Getter ObjectMapper jsonSerDes;
@Getter JCoinbaseProperties properties;
@Getter AuthenticationService authService;
DataService dataService;
UserService userService;
/**
* This method provides a {@link DataService} allowing you to request coinbase public data using
* it's api
*
* @return a {@link DataService}
*/
public DataService data() {
return dataService;
}
/**
* This method provides a {@link UserService} allowing you to request coinbase public data using
* it's api
*
* <p>Warning : this method throws a {@link JCoinbaseException} if you don't properly build your
* JCoinbaseClient by providing your api key and secret
*
* @return a {@link UserService}
*/
public UserService user() {
val allowed = authService.allow(this);
if (allowed.isLeft()) {
manageNotAllowed(allowed.getLeft());
}
return userService;
}
/**
* This protected method build a new JCoinbaseClient with the given parameters
*
* @param apiKey the coinbase api key
* @param secret the coinbase api secret
* @param apiVersion the coinbase api version
* @param timeout the wanted timeout for http requests
* @param threadSafe a boolean defining if the instance should be a thread safe singleton
* @return a {@link JCoinbaseClient}
*/
protected JCoinbaseClient build(
final String apiKey,
final String secret,
final String apiVersion,
final long timeout,
final boolean threadSafe) {
log.info("Start building new JCoinbase client !");
buildJsonSerDes();
buildProperties(apiKey, secret, apiVersion, threadSafe);
buildAuthService();
buildDataService();
buildUserService();
buildHttpClient(timeout);
log.info("JCoinbase client successfully built !");
return this;
}
/** Method building a new Jackson ObjectMapper with a custom configuration */
private void buildJsonSerDes() {
this.jsonSerDes =
new ObjectMapper()
.findAndRegisterModules()
.registerModule(new VavrModule())
.registerModule(new JavaTimeModule())
.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()))
.configure(WRITE_DATES_AS_TIMESTAMPS, false);
}
/**
* Build the client properties calling the {@link JCoinbasePropertiesFactory}
*
* @param apiKey the coinbase api key
* @param secret the coinbase api secret
* @param apiVersion the coinbase api version
* @param threadSafe a boolean defining if the instance should be a thread safe singleton
*/
private void buildProperties(
final String apiKey, final String secret, final String apiVersion, final boolean threadSafe) {
this.properties = JCoinbasePropertiesFactory.build(apiKey, secret, apiVersion, threadSafe);
}
/** Build a new {@link AuthenticationService} */
private void buildAuthService() {
this.authService = new AuthenticationService();
}
/** Build a new {@link DataService} */
private void buildDataService() {
this.dataService = new DataService(this, new CoinbaseDataService());
}
/** Build a new {@link UserService} */
private void buildUserService() {
this.userService = new UserService(this, new CoinbaseUserService(), authService);
}
/** Build a new {@link HttpClient} */
private void buildHttpClient(final long timeout) {
this.httpClient =
HttpClient.newBuilder()
.connectTimeout(Duration.of(timeout, SECONDS))
.followRedirects(NEVER)
.build();
}
/**
* Method to call when the request to a service is not allow
*
* @param throwable a throwable to log
*/
private void manageNotAllowed(final Throwable throwable) {
ErrorManagerService.manageOnError(
new JCoinbaseException(throwable),
"Unable to allow this request. Please make sure you correctly build your JCoinbaseClient with API KEY and SECRET",
throwable);
}
}