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

Java.libraries.retrofit2.ApiClient.mustache Maven / Gradle / Ivy

There is a newer version: 3.0.0-rc1
Show newest version
package {{invokerPackage}};

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder;
{{^java8}}
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
{{/java8}}
{{#java8}}
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
{{/java8}}
import retrofit2.Converter;
import retrofit2.Retrofit;
{{#useRxJava}}
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
{{/useRxJava}}
{{#useRxJava2}}
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
{{/useRxJava2}}
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;

import {{invokerPackage}}.auth.HttpBasicAuth;
import {{invokerPackage}}.auth.ApiKeyAuth;
import {{invokerPackage}}.auth.OAuth;
import {{invokerPackage}}.auth.OAuth.AccessTokenListener;
import {{invokerPackage}}.auth.OAuthFlow;

public class ApiClient {

  private Map apiAuthorizations;
  private OkHttpClient.Builder okBuilder;
  private Retrofit.Builder adapterBuilder;

  public ApiClient() {
    apiAuthorizations = new LinkedHashMap();
    createDefaultAdapter();
  }

  public ApiClient(String[] authNames) {
    this();
    for(String authName : authNames) {
      {{#hasAuthMethods}}
      Interceptor auth;
      {{#authMethods}}if ("{{name}}".equals(authName)) {
      {{#isBasic}}
        auth = new HttpBasicAuth();
      {{/isBasic}}
      {{#isApiKey}}
        auth = new ApiKeyAuth({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}");
      {{/isApiKey}}
      {{#isOAuth}}
        auth = new OAuth(OAuthFlow.{{flow}}, "{{authorizationUrl}}", "{{tokenUrl}}", "{{#scopes}}{{scope}}{{#hasMore}}, {{/hasMore}}{{/scopes}}");
      {{/isOAuth}}
      } else {{/authMethods}}{
        throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names");
      }
      addAuthorization(authName, auth);
      {{/hasAuthMethods}}
      {{^hasAuthMethods}}
      throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names");
      {{/hasAuthMethods}}
    }
  }

  /**
   * Basic constructor for single auth name
   * @param authName Authentication name
   */
  public ApiClient(String authName) {
    this(new String[]{authName});
  }

  /**
   * Helper constructor for single api key
   * @param authName Authentication name
   * @param apiKey API key
   */
  public ApiClient(String authName, String apiKey) {
    this(authName);
    this.setApiKey(apiKey);
  }

  /**
   * Helper constructor for single basic auth or password oauth2
   * @param authName Authentication name
   * @param username Username
   * @param password Password
   */
  public ApiClient(String authName, String username, String password) {
    this(authName);
    this.setCredentials(username,  password);
  }

  /**
   * Helper constructor for single password oauth2
   * @param authName Authentication name
   * @param clientId Client ID
   * @param secret Client Secret
   * @param username Username
   * @param password Password
   */
  public ApiClient(String authName, String clientId, String secret, String username, String password) {
    this(authName);
    this.getTokenEndPoint()
      .setClientId(clientId)
      .setClientSecret(secret)
      .setUsername(username)
      .setPassword(password);
  }

  public void createDefaultAdapter() {
    Gson gson = new GsonBuilder()
      .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
      {{^java8}}
      .registerTypeAdapter(DateTime.class, new DateTimeTypeAdapter())
      {{/java8}}
      {{#java8}}
      .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeTypeAdapter())
      {{/java8}}
      .registerTypeAdapter(LocalDate.class, new LocalDateTypeAdapter())
      .create();

    okBuilder = new OkHttpClient.Builder();

    String baseUrl = "{{{basePath}}}";
    if(!baseUrl.endsWith("/"))
      baseUrl = baseUrl + "/";

    adapterBuilder = new Retrofit
      .Builder()
      .baseUrl(baseUrl)
      {{#useRxJava}}
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
      {{/useRxJava}}
      {{#useRxJava2}}
      .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
      {{/useRxJava2}}
      .addConverterFactory(ScalarsConverterFactory.create())
      .addConverterFactory(GsonCustomConverterFactory.create(gson));
  }

  public  S createService(Class serviceClass) {
    return adapterBuilder
      .client(okBuilder.build())
      .build()
      .create(serviceClass);

  }

  /**
   * Helper method to configure the first api key found
   * @param apiKey API key
   */
  private void setApiKey(String apiKey) {
    for(Interceptor apiAuthorization : apiAuthorizations.values()) {
      if (apiAuthorization instanceof ApiKeyAuth) {
        ApiKeyAuth keyAuth = (ApiKeyAuth) apiAuthorization;
        keyAuth.setApiKey(apiKey);
        return;
      }
    }
  }

  /**
   * Helper method to configure the username/password for basic auth or password oauth
   * @param username Username
   * @param password Password
   */
  private void setCredentials(String username, String password) {
    for(Interceptor apiAuthorization : apiAuthorizations.values()) {
      if (apiAuthorization instanceof HttpBasicAuth) {
        HttpBasicAuth basicAuth = (HttpBasicAuth) apiAuthorization;
        basicAuth.setCredentials(username, password);
        return;
      }
      if (apiAuthorization instanceof OAuth) {
        OAuth oauth = (OAuth) apiAuthorization;
        oauth.getTokenRequestBuilder().setUsername(username).setPassword(password);
        return;
      }
    }
  }

  /**
   * Helper method to configure the token endpoint of the first oauth found in the apiAuthorizations (there should be only one)
   * @return Token request builder
   */
  public TokenRequestBuilder getTokenEndPoint() {
    for(Interceptor apiAuthorization : apiAuthorizations.values()) {
      if (apiAuthorization instanceof OAuth) {
        OAuth oauth = (OAuth) apiAuthorization;
        return oauth.getTokenRequestBuilder();
      }
    }
    return null;
  }

  /**
   * Helper method to configure authorization endpoint of the first oauth found in the apiAuthorizations (there should be only one)
   * @return Authentication request builder
   */
  public AuthenticationRequestBuilder getAuthorizationEndPoint() {
    for(Interceptor apiAuthorization : apiAuthorizations.values()) {
      if (apiAuthorization instanceof OAuth) {
        OAuth oauth = (OAuth) apiAuthorization;
        return oauth.getAuthenticationRequestBuilder();
      }
    }
    return null;
  }

  /**
   * Helper method to pre-set the oauth access token of the first oauth found in the apiAuthorizations (there should be only one)
   * @param accessToken Access token
   */
  public void setAccessToken(String accessToken) {
    for(Interceptor apiAuthorization : apiAuthorizations.values()) {
      if (apiAuthorization instanceof OAuth) {
        OAuth oauth = (OAuth) apiAuthorization;
        oauth.setAccessToken(accessToken);
        return;
      }
    }
  }

  /**
   * Helper method to configure the oauth accessCode/implicit flow parameters
   * @param clientId Client ID
   * @param clientSecret Client secret
   * @param redirectURI Redirect URI
   */
  public void configureAuthorizationFlow(String clientId, String clientSecret, String redirectURI) {
    for(Interceptor apiAuthorization : apiAuthorizations.values()) {
      if (apiAuthorization instanceof OAuth) {
        OAuth oauth = (OAuth) apiAuthorization;
        oauth.getTokenRequestBuilder()
          .setClientId(clientId)
          .setClientSecret(clientSecret)
          .setRedirectURI(redirectURI);
        oauth.getAuthenticationRequestBuilder()
          .setClientId(clientId)
          .setRedirectURI(redirectURI);
        return;
      }
    }
  }

  /**
   * Configures a listener which is notified when a new access token is received.
   * @param accessTokenListener Access token listener
   */
  public void registerAccessTokenListener(AccessTokenListener accessTokenListener) {
    for(Interceptor apiAuthorization : apiAuthorizations.values()) {
      if (apiAuthorization instanceof OAuth) {
        OAuth oauth = (OAuth) apiAuthorization;
        oauth.registerAccessTokenListener(accessTokenListener);
        return;
      }
    }
  }

  /**
   * Adds an authorization to be used by the client
   * @param authName Authentication name
   * @param authorization Authorization interceptor
   */
  public void addAuthorization(String authName, Interceptor authorization) {
    if (apiAuthorizations.containsKey(authName)) {
      throw new RuntimeException("auth name \"" + authName + "\" already in api authorizations");
    }
    apiAuthorizations.put(authName, authorization);
    okBuilder.addInterceptor(authorization);
  }

  public Map getApiAuthorizations() {
    return apiAuthorizations;
  }

  public void setApiAuthorizations(Map apiAuthorizations) {
    this.apiAuthorizations = apiAuthorizations;
  }

  public Retrofit.Builder getAdapterBuilder() {
    return adapterBuilder;
  }

  public void setAdapterBuilder(Retrofit.Builder adapterBuilder) {
    this.adapterBuilder = adapterBuilder;
  }

  public OkHttpClient.Builder getOkBuilder() {
    return okBuilder;
  }

  public void addAuthsToOkBuilder(OkHttpClient.Builder okBuilder) {
    for(Interceptor apiAuthorization : apiAuthorizations.values()) {
      okBuilder.addInterceptor(apiAuthorization);
    }
  }

  /**
   * Clones the okBuilder given in parameter, adds the auth interceptors and uses it to configure the Retrofit
   * @param okClient An instance of OK HTTP client
   */
  public void configureFromOkclient(OkHttpClient okClient) {
    this.okBuilder = okClient.newBuilder();
    addAuthsToOkBuilder(this.okBuilder);
  }
}

/**
 * This wrapper is to take care of this case:
 * when the deserialization fails due to JsonParseException and the
 * expected type is String, then just return the body string.
 */
class GsonResponseBodyConverterToString implements Converter {

  private final Gson gson;
  private final Type type;

  GsonResponseBodyConverterToString(Gson gson, Type type) {
    this.gson = gson;
    this.type = type;
  }

  @Override public T convert(ResponseBody value) throws IOException {
    String returned = value.string();
    try {
      return gson.fromJson(returned, type);
    }
    catch (JsonParseException e) {
      return (T) returned;
    }
  }
}

class GsonCustomConverterFactory extends Converter.Factory {

  private final Gson gson;
  private final GsonConverterFactory gsonConverterFactory;

  public static GsonCustomConverterFactory create(Gson gson) {
    return new GsonCustomConverterFactory(gson);
  }

  private GsonCustomConverterFactory(Gson gson) {
    if (gson == null)
      throw new NullPointerException("gson == null");
    this.gson = gson;
    this.gsonConverterFactory = GsonConverterFactory.create(gson);
  }

  @Override
  public Converter responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
    if (type.equals(String.class))
      return new GsonResponseBodyConverterToString(gson, type);
    else
      return gsonConverterFactory.responseBodyConverter(type, annotations, retrofit);
  }

  @Override
  public Converter requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
    return gsonConverterFactory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, retrofit);
  }
}

{{^java8}}
/**
 * Gson TypeAdapter for Joda DateTime type
 */
class DateTimeTypeAdapter extends TypeAdapter {

  private final DateTimeFormatter parseFormatter = ISODateTimeFormat.dateOptionalTimeParser();
  private final DateTimeFormatter printFormatter = ISODateTimeFormat.dateTime();

  @Override
  public void write(JsonWriter out, DateTime date) throws IOException {
    if (date == null) {
        out.nullValue();
    } else {
        out.value(printFormatter.print(date));
    }
  }

  @Override
  public DateTime read(JsonReader in) throws IOException {
    switch (in.peek()) {
      case NULL:
        in.nextNull();
        return null;
      default:
        String date = in.nextString();
        return parseFormatter.parseDateTime(date);
    }
  }
}

/**
 * Gson TypeAdapter for Joda LocalDate type
 */
class LocalDateTypeAdapter extends TypeAdapter {

  private final DateTimeFormatter formatter = ISODateTimeFormat.date();

  @Override
  public void write(JsonWriter out, LocalDate date) throws IOException {
    if (date == null) {
      out.nullValue();
    } else {
      out.value(formatter.print(date));
    }
  }

  @Override
  public LocalDate read(JsonReader in) throws IOException {
    switch (in.peek()) {
      case NULL:
        in.nextNull();
        return null;
      default:
        String date = in.nextString();
        return formatter.parseLocalDate(date);
    }
  }
}
{{/java8}}
{{#java8}}
/**
 * Gson TypeAdapter for jsr310 OffsetDateTime type
 */
class OffsetDateTimeTypeAdapter extends TypeAdapter {

  private final DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;

  @Override
  public void write(JsonWriter out, OffsetDateTime date) throws IOException {
    if (date == null) {
      out.nullValue();
    } else {
      out.value(formatter.format(date));
    }
  }

  @Override
  public OffsetDateTime read(JsonReader in) throws IOException {
    switch (in.peek()) {
      case NULL:
        in.nextNull();
        return null;
      default:
        String date = in.nextString();
        if (date.endsWith("+0000")) {
            date = date.substring(0, date.length()-5) + "Z";
        }
        return OffsetDateTime.parse(date, formatter);
    }
  }
}

/**
 * Gson TypeAdapter for jsr310 LocalDate type
 */
class LocalDateTypeAdapter extends TypeAdapter {

  private final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE;

  @Override
  public void write(JsonWriter out, LocalDate date) throws IOException {
    if (date == null) {
      out.nullValue();
    } else {
      out.value(formatter.format(date));
    }
  }

  @Override
  public LocalDate read(JsonReader in) throws IOException {
    switch (in.peek()) {
      case NULL:
        in.nextNull();
        return null;
      default:
        String date = in.nextString();
        return LocalDate.parse(date, formatter);
    }
  }
}
{{/java8}}