The net is vast
プログラミングや、コンピュータなどの備忘録です。 主にRuby, Java, Linux, 等を扱います。アルゴリズムも扱いたいな。
16:26

Product Advertising APIの日本用Restクライアント(Java)

Category: , By jx
dankogaiさんが、PerlのProduct Advertising APIライブラリを作ってた。便乗して、Java。 Amazonの新しいProduct Advertising APIのRestのリクエストの作り方は前回のエントリで説明しました。このRestクライアントは、Amazonのドキュメントに載っています。しかし、その例は米国用になっているので、ちょっとだけ修正してあげる必要が在ります。 具体的には、endpointをecs.amazonaws.jpに変更します。これだけで、日本のものに適用出来るようになります。なお、使用方法ですが、次のようにします。簡単ですね。
  // リクエストのキーと値のMap
  Map<String, String> keyMap = new HashMap<String, String>();
  keyMap.put("AWSAccessKeyId", "000000000000000");
  keyMap.put("Version", "2008-08-19");
  keyMap.put("Operation", "ItemLookup");
  keyMap.put("ItemId", "4877712399");
  keyMap.put("ResponseGroup", "Medium");
  keyMap.put("AssociateTag", "jx-22");
  keyMap.put("Service", "AWSECommerceService");
  SignedRequestsHelper signedRequestsHelper = new SignedRequestsHelper();
  String urlStr = signedRequestsHelper.sign(keyMap);
  URL url = new URL(urlStr);
  HttpURLConnection connection = (HttpURLConnection) url
    .openConnection();
日本用に修正したJava Rest クライアント
package com.amazon.associates.sample;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TimeZone;
import java.util.TreeMap;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import net.jirox.shohyo.exception.ShohyoFatalException;

import org.apache.commons.codec.binary.Base64;

public class SignedRequestsHelper {
 private static final String UTF8_CHARSET = "UTF-8";
 private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
 private static final String REQUEST_URI = "/onca/xml";
 private static final String REQUEST_METHOD = "GET";

 //日本用
 private String endpoint = "ecs.amazonaws.jp"; // must be lowercase
 private String awsAccessKeyId = "YOUR ACCESS KEY ID";
 private String awsSecretKey = "YOUR SECRET KEY";

 private SecretKeySpec secretKeySpec = null;
 private Mac mac = null;

 public SignedRequestsHelper() throws ShohyoFatalException {
  byte[] secretyKeyBytes;
  try {
   secretyKeyBytes = awsSecretKey.getBytes(UTF8_CHARSET);
   secretKeySpec = new SecretKeySpec(secretyKeyBytes,
     HMAC_SHA256_ALGORITHM);
   mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
   mac.init(secretKeySpec);
  } catch (UnsupportedEncodingException e) {
   throw new ShohyoFatalException(e);
  } catch (NoSuchAlgorithmException e) {
   throw new ShohyoFatalException(e);
  } catch (InvalidKeyException e) {
   throw new ShohyoFatalException(e);
  }
 }

 public String sign(Map<String, String> params) {
  params.put("AWSAccessKeyId", awsAccessKeyId);
  params.put("Timestamp", timestamp());

  SortedMap<String, String> sortedParamMap = new TreeMap<String, String>(
    params);
  String canonicalQS = canonicalize(sortedParamMap);
  String toSign = REQUEST_METHOD + "\n" + endpoint + "\n" + REQUEST_URI
    + "\n" + canonicalQS;

  String hmac = hmac(toSign);
  String sig = percentEncodeRfc3986(hmac);
  String url = "http://" + endpoint + REQUEST_URI + "?" + canonicalQS
    + "&Signature=" + sig;

  return url;
 }

 private String hmac(String stringToSign) {
  String signature = null;
  byte[] data;
  byte[] rawHmac;
  try {
   data = stringToSign.getBytes(UTF8_CHARSET);
   rawHmac = mac.doFinal(data);
   Base64 encoder = new Base64();
   signature = new String(encoder.encode(rawHmac));
  } catch (UnsupportedEncodingException e) {
   throw new RuntimeException(UTF8_CHARSET + " is unsupported!", e);
  }
  return signature;
 }

 private String timestamp() {
  String timestamp = null;
  Calendar cal = Calendar.getInstance();
  DateFormat dfm = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
  dfm.setTimeZone(TimeZone.getTimeZone("GMT"));
  timestamp = dfm.format(cal.getTime());
  return timestamp;
 }

 private String canonicalize(SortedMap<String, String> sortedParamMap) {
  if (sortedParamMap.isEmpty()) {
   return "";
  }

  StringBuffer buffer = new StringBuffer();
  Iterator<Map.Entry<String, String>> iter = sortedParamMap.entrySet()
    .iterator();

  while (iter.hasNext()) {
   Map.Entry<String, String> kvpair = iter.next();
   buffer.append(percentEncodeRfc3986(kvpair.getKey()));
   buffer.append("=");
   buffer.append(percentEncodeRfc3986(kvpair.getValue()));
   if (iter.hasNext()) {
    buffer.append("&");
   }
  }
  String cannoical = buffer.toString();
  return cannoical;
 }

 private String percentEncodeRfc3986(String s) {
  String out;
  try {
   out = URLEncoder.encode(s, UTF8_CHARSET).replace("+", "%20")
     .replace("*", "%2A").replace("%7E", "~");
  } catch (UnsupportedEncodingException e) {
   out = s;
  }
  return out;
 }

}
 

0 comments so far.

Something to say?