mizo0203/lily-white-line-notify

View on GitHub
src/main/java/com/mizo0203/lilywhite/repo/LineRepository.java

Summary

Maintainability
B
6 hrs
Test Coverage
package com.mizo0203.lilywhite.repo;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mizo0203.lilywhite.domain.Define;
import com.mizo0203.lilywhite.repo.line.data.*;
import com.mizo0203.lilywhite.util.HttpUtil;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.utils.URIBuilder;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/* package */ class LineRepository {

  private static final Logger LOG = Logger.getLogger(LineRepository.class.getName());
  private static final String LINE_NOTIFY_API_AUTHORIZE_OAUTH_URL_STR =
      "https://notify-bot.line.me/oauth/authorize";
  private static final String LINE_NOTIFY_API_TOKEN_OAUTH_URL_STR =
      "https://notify-bot.line.me/oauth/token";
  private static final String LINE_NOTIFY_API_NOTIFY_URL_STR =
      "https://notify-api.line.me/api/notify";
  private static final String LINE_NOTIFY_API_STATUS_URL_STR =
      "https://notify-api.line.me/api/status";
  private static final String LINE_NOTIFY_API_REVOKE_URL_STR =
      "https://notify-api.line.me/api/revoke";

  @SuppressWarnings("EmptyMethod")
  public void destroy() {
    // NOP
  }

  @Nullable
  public String buildAuthorizeOauthRedirectUrlString(
      String client_id, String redirect_uri_str, String state) {
    try {
      return new URIBuilder(LINE_NOTIFY_API_AUTHORIZE_OAUTH_URL_STR)
          .setParameter("response_type", "code")
          .setParameter("client_id", client_id)
          .setParameter("redirect_uri", redirect_uri_str)
          .setParameter("scope", "notify")
          .setParameter("state", state) // FIXME: ユーザのセッションIDから生成されるハッシュ値などを指定
          .setParameter("response_mode", "form_post")
          .build()
          .toString();
    } catch (URISyntaxException e) {
      LOG.log(Level.SEVERE, "", e);
      return null;
    }
  }

  public void tokenOauth(
      String code,
      String client_id,
      String client_secret,
      @Nonnull Callback<AccessToken> callback) {
    Map<String, String> reqProp = new HashMap<>();
    reqProp.put("Content-Type", "application/x-www-form-urlencoded");

    Map<String, String> params = new HashMap<>();
    params.put("grant_type", "authorization_code");
    params.put("code", code);
    params.put("redirect_uri", Define.REDIRECT_URI_STR);
    params.put("client_id", client_id);
    params.put("client_secret", client_secret);

    try {
      HttpUtil.post(
          new URL(LINE_NOTIFY_API_TOKEN_OAUTH_URL_STR),
          reqProp,
          params,
          connection -> {
            try {
              if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                callback.response(null, null);
                return;
              }
              String body = IOUtils.toString(connection.getInputStream(), StandardCharsets.UTF_8);
              AccessToken accessToken = new ObjectMapper().readValue(body, AccessToken.class);
              callback.response(null, accessToken);
            } catch (IOException e) {
              LOG.log(Level.SEVERE, "", e);
              callback.response(null, null);
            }
          });
    } catch (MalformedURLException e) {
      LOG.log(Level.SEVERE, "", e);
      callback.response(null, null);
    }
  }

  public void notify(
      @Nonnull String access_token,
      @Nonnull String message,
      @Nullable String imageThumbnail,
      @Nullable String imageFullsize,
      @Nullable String imageFile,
      @Nullable Number stickerPackageId,
      @Nullable Number stickerId,
      @Nonnull Callback<ResponseNotifyData> callback) {
    Map<String, String> reqProp = new HashMap<>();
    reqProp.put("Content-Type", "application/x-www-form-urlencoded");
    reqProp.put("Authorization", "Bearer " + access_token);

    Map<String, String> params = new HashMap<>();
    params.put("message", message);
    params.put("imageThumbnail", imageThumbnail);
    params.put("imageFullsize", imageFullsize);
    params.put("imageFile", imageFile);
    params.put("stickerPackageId", stickerPackageId != null ? stickerPackageId.toString() : null);
    params.put("stickerId", stickerId != null ? stickerId.toString() : null);

    try {
      HttpUtil.post(
          new URL(LINE_NOTIFY_API_NOTIFY_URL_STR),
          reqProp,
          params,
          connection -> {
            ResponseApiRateLimit apiRateLimit = parseResponseApiRateLimit(connection);
            try {
              if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                callback.response(apiRateLimit, null);
                return;
              }
              String body = IOUtils.toString(connection.getInputStream(), StandardCharsets.UTF_8);
              ResponseNotifyData responseNotifyData =
                  new ObjectMapper().readValue(body, ResponseNotifyData.class);
              LOG.info("responseNotifyData.getStatus(): " + responseNotifyData.getStatus());
              LOG.info("responseNotifyData.getMessage(): " + responseNotifyData.getMessage());
              callback.response(apiRateLimit, responseNotifyData);
            } catch (IOException e) {
              LOG.log(Level.SEVERE, "", e);
              callback.response(apiRateLimit, null);
            }
          });
    } catch (MalformedURLException e) {
      LOG.log(Level.SEVERE, "", e);
      callback.response(null, null);
    }
  }

  public void status(@Nonnull String access_token, @Nonnull Callback<ResponseStatusData> callback) {
    Map<String, String> reqProp = new HashMap<>();
    reqProp.put("Authorization", "Bearer " + access_token);

    try {
      HttpUtil.get(
          new URL(LINE_NOTIFY_API_STATUS_URL_STR),
          reqProp,
          connection -> {
            ResponseApiRateLimit apiRateLimit = parseResponseApiRateLimit(connection);
            try {
              if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                callback.response(apiRateLimit, null);
                return;
              }
              String body = IOUtils.toString(connection.getInputStream(), StandardCharsets.UTF_8);
              ResponseStatusData responseStatusData =
                  new ObjectMapper().readValue(body, ResponseStatusData.class);
              LOG.info("responseStatusData.getStatus(): " + responseStatusData.getStatus());
              LOG.info("responseStatusData.getMessage(): " + responseStatusData.getMessage());
              LOG.info("responseStatusData.getTargetType(): " + responseStatusData.getTargetType());
              LOG.info("responseStatusData.getTarget(): " + responseStatusData.getTarget());
              callback.response(apiRateLimit, responseStatusData);
            } catch (IOException e) {
              LOG.log(Level.SEVERE, "", e);
              callback.response(apiRateLimit, null);
            }
          });
    } catch (MalformedURLException e) {
      LOG.log(Level.SEVERE, "", e);
      callback.response(null, null);
    }
  }

  public void revoke(@Nonnull String access_token, @Nonnull Callback<ResponseRevokeData> callback) {
    Map<String, String> reqProp = new HashMap<>();
    reqProp.put("Content-Type", "application/x-www-form-urlencoded");
    reqProp.put("Authorization", "Bearer " + access_token);

    try {
      HttpUtil.post(
          new URL(LINE_NOTIFY_API_REVOKE_URL_STR),
          reqProp,
          new HashMap<>(),
          connection -> {
            try {
              if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                callback.response(null, null);
                return;
              }
              String body = IOUtils.toString(connection.getInputStream(), StandardCharsets.UTF_8);
              ResponseRevokeData responseRevokeData =
                  new ObjectMapper().readValue(body, ResponseRevokeData.class);
              LOG.info("responseRevokeData.getStatus(): " + responseRevokeData.getStatus());
              LOG.info("responseRevokeData.getMessage(): " + responseRevokeData.getMessage());
              callback.response(null, responseRevokeData);
            } catch (IOException e) {
              LOG.log(Level.SEVERE, "", e);
              callback.response(null, null);
            }
          });
    } catch (MalformedURLException e) {
      LOG.log(Level.SEVERE, "", e);
      callback.response(null, null);
    }
  }

  private ResponseApiRateLimit parseResponseApiRateLimit(URLConnection connection) {
    try {
      int limit = Integer.parseInt(connection.getHeaderField("X-RateLimit-Limit"));
      int remaining = Integer.parseInt(connection.getHeaderField("X-RateLimit-Remaining"));
      int imageLimit = Integer.parseInt(connection.getHeaderField("X-RateLimit-ImageLimit"));
      int imageRemaining =
          Integer.parseInt(connection.getHeaderField("X-RateLimit-ImageRemaining"));
      Date reset = new Date(Long.parseLong(connection.getHeaderField("X-RateLimit-Reset")));
      LOG.info("X-RateLimit-Limit:          " + limit);
      LOG.info("X-RateLimit-Remaining:      " + remaining);
      LOG.info("X-RateLimit-ImageLimit:     " + imageLimit);
      LOG.info("X-RateLimit-ImageRemaining: " + imageRemaining);
      LOG.info("X-RateLimit-Reset:          " + reset);
      return new ResponseApiRateLimit(limit, remaining, imageLimit, imageRemaining, reset);
    } catch (NumberFormatException e) {
      e.printStackTrace();
      return null;
    }
  }

  public interface Callback<T> {

    void response(@Nullable ResponseApiRateLimit apiRateLimit, @Nullable T res);
  }
}