分类
原创作品 技术

亚马逊联盟API上手指南 – Amazon.cn Product Advertising API quick start

该指南旨在帮助使用亚马逊联盟Product Advertising API的开发人员快速上手,开发出一个可以运行的样例程序。该指南的目标读者是对WebService、RESTful Service有一定了解的Java开发人员。

主要步骤:

  1. 注册亚马逊联盟账号;
  2. 注册联盟开发者账号;
  3. 修改并调试样例程序。

注册亚马逊联盟账号

访问亚马逊联盟网站http://associates.amazon.cn,确保选择地区为“中国”,点击“免费加入”按钮,会跳转到登录注册页面,这里可以直接使用你已经注册过的亚马逊(中国)账号,或者新注册一个账号。

下一步进入向导页面,第一步“帐户信息”中选择或新加一个地址,第二步“我的网站模式”照实填(是的,你需要有一个网站,从导购网站到博客都可以),第三步完成即可。提示添加付款信息,输入一张有效银行卡即可,这一步骤以后做也行。

保持登录状态进入联盟管理界面。比如你在第二步中输入的网站ID为“MyWebsite”,那你的默认跟踪ID将为“mywebsite-23”。跟踪ID又叫Associate Tag,用于在用户实际购买过程中识别你的账号,以保证在发生购买时给你分配提成。点击主页左侧“跟踪代码管理”,可以添加额外的跟踪ID,比如“mywebsite-channel1”,点击“搜索”(其实就是创建),会生成“mywebsite-channel1-23”(如果跟已有的重名会生成其他后缀)。

注册联盟开发者账号

登录到联盟管理界面中,点击“Product Advertising API”页签,会跳转到Product Advertising API的介绍页面。基本上这个页面里所有链接都是有用的,但你可以先点击右边的“现在注册按钮”。这里会跳转到美国亚马逊网站的登录注册界面,注意亚马逊美国和亚马逊中国的账号体系是互相独立的,这里可以用你已经注册过的亚马逊美国账号,或新注册一个(可以使用与亚马逊中国相同的邮箱,也可以不同)。进入第二步,账户信息,这次界面是英文的,填英文或直接填中文都可以,记得下面“Check here to indicate……”要打勾,还有输入正确的图片验证码,点击“完成注册”。

在成功界面,点击“管理您的帐户”链接,跳转到管理页面,在“访问标识”栏,点击“点击这里”,你会发现你跳转到了高大上的AWS亚马逊云的管理页面上。如果有“Attention”提示,不用管它,勾选“I understand”,点击“Continue”即可关闭提示。在“Access Credentials”章节的“Access Keys”标签下,你会看到你的“Access Key ID”是一串字母数字(20个字符),点击“Secret Access Key”列对应的“Show”链接,会弹一个提示框,里面会显示另一串字母数字(40个字符),这就是之后会用的Secret Key。因为超过多少时间后就不能在查看Secret Key了,建议把这对Access Key ID和Secret Key记录在一个安全的地方。

 

修改并调试样例程序

回到“管理您的帐户”页面,点击左边的“示例代码”,会来到一个列表页面,里边有各种语言的样例程序,比如node.js、PHP、Ruby、C#、Perl、Java,我们比较关心Java。点击“Product Advertising API Signed Requests Sample Code – Java REST/QUERY”,再点击“Download”下载程序包。Java SOAP的样例也是可以用的,但相比而言REST这个版本更简单些。需要注意的是,经笔者测试,截止到14年3月,在北京联通网络访问AWS系列站点有时会有些慢甚至打不开,挂上香港或国外代理服务器即可恢复正常(API接口调用则不存在这个问题)。

将下载的amazon-product-advt-api-sample-java-query.zip解压,在Eclipse里新建一个普通Java工程,把src目录拷贝进去。然后你会发现工程缺少依赖类库无法编译,去Apache网站http://commons.apache.org/proper/commons-codec/下载一个commons-codec.jar,1.3版本以上即可,放到项目lib目录中,并加入Build Path,编译就应该通过了。

com.amazon.advertising.api.sample.SignedRequestsHelper这个类没有什么要改的,用于生产环境都可以。但com.amazon.advertising.api.sample.ItemLookupSample类里有一些需要调整的地方:

  1. Endpoint(即API所在的服务器URL)修改为亚马逊中国的服务器。别找了,截止到14年3月的版本,注释里都没列中国,但从在线文档(Anatomy of a REST Request)可以找到,CN的Endpoint包括:

    http://webservices.amazon.cn/onca/xml
    https://webservices.amazon.cn/onca/xml

  2. 添加一个Associate Tag常量,并作为参数传到API里去。这个就是你一开始注册的联盟账号里的跟踪ID,没有这个是算不了钱的。
  3. 修改AWS_ACCESS_KEY_ID和AWS_SECRET_KEY为上一章注册的开发者账号中所提供的那对Access Key ID和Secret Key。
  4. 调整API Version参数,样例中的“2009-03-31”版本已经过期,修改为“2011-08-01”。
  5. 样例中的ITEM_ID是美国的商品,改成中国的“B00D2J9ETE”。

执行ItemLookupSample,Run as Java Application。正确的话,会在Console控制台里打出“Signed Title is “Kindle Fire HDX平板电脑””的字样。程序会调用API两次,其实只是为了演示SignedRequestsHelper.sign()方法的两种重载。

如果程序报错,尝试把Console里打出来的“Signed Request is http://webservices.amazon.cn/onca/xml?AWSAccessKeyId=……”那行里的URL复制下来并在浏览器打开,观察返回的XML即可发现问题,比如认证失败、参数无效之类的错误,都会有提示。

为了大家方便,笔者把自己修改版本的SignedRequestsHelper附在文章最后,替换即可。

基于这个样例程序,相信大家已经可以快速上手,下一步可以查看官方Developer Guide文档(在线查看下载离线PDF),开发更多的业务功能,同时也建议大家将API返回XML的解析处理做的更强壮更灵活些。

声明:本文中涉及到的样例程序版权归亚马逊所有,笔者的修改仅为展示API能力,笔者不对其中产生的任何bug负责。

附录

笔者的ItemLookupSample.java源码

public class ItemLookupSample {
    /**
     * Your associate tag, as taken from Associate administration page.
     */
    private static final String ASSOCIATE_TAG = "YOUR_ASSOCIATE_TAG_HERE";
    /**
     * Your AWS Access Key ID, as taken from the AWS Your Account page.
     */
    private static final String AWS_ACCESS_KEY_ID = "YOUR_ACCESS_KEY_ID_HERE";

    /**
     * Your AWS Secret Key corresponding to the above ID, as taken from the AWS
     * Your Account page.
     */
    private static final String AWS_SECRET_KEY = "YOUR_SECRET_KEY_HERE";

    /**
     * Use one of the following end-points, according to the region you are
     * interested in:
     * 
     *      US: ecs.amazonaws.com 
     *      CA: ecs.amazonaws.ca 
     *      UK: ecs.amazonaws.co.uk 
     *      DE: ecs.amazonaws.de 
     *      FR: ecs.amazonaws.fr 
     *      JP: ecs.amazonaws.jp
     *      CN: webservices.amazon.cn
     */
    private static final String ENDPOINT = "webservices.amazon.cn";

    /**
     * The Item ID to lookup. The value below was selected for the US locale.
     * You can choose a different value if this value does not work in the
     * locale of your choice.
     */
    private static final String ITEM_ID = "B00D2J9ETE";

    public static void main(String[] args) {
        // Set up the signed requests helper
        SignedRequestsHelper helper;
        try {
            helper = SignedRequestsHelper.getInstance(ENDPOINT, AWS_ACCESS_KEY_ID, AWS_SECRET_KEY);
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }

        String requestUrl = null;
        String title = null;

        // The helper can sign requests in two forms - map form and string form.

        // Here is an example in map form, where the request parameters are stored in a map.
        System.out.println("Map form example:");
        Map<String, String> params = new HashMap<String, String>();
        params.put("Service", "AWSECommerceService");
        params.put("Version", "2011-08-01");
        params.put("AssociateTag", ASSOCIATE_TAG);
        params.put("Operation", "ItemLookup");
        params.put("ItemId", ITEM_ID);
        params.put("ResponseGroup", "Small");

        requestUrl = helper.sign(params);
        System.out.println("Signed Request is " + requestUrl);

        title = fetchTitle(requestUrl);
        System.out.println("Signed Title is \"" + title + "\"");
        System.out.println();

        //Here is an example with string form, where the requests parameters have already been concatenated
        // into a query string. 
        System.out.println("String form example:");
        String queryString = "Service=AWSECommerceService&Version=2011-08-01&AssociateTag=" 
                + ASSOCIATE_TAG + "&Operation=ItemLookup&ResponseGroup=Small&ItemId="
                + ITEM_ID;
        requestUrl = helper.sign(queryString);
        System.out.println("Request is " + requestUrl);

        title = fetchTitle(requestUrl);
        System.out.println("Title is \"" + title + "\"");
        System.out.println();
    }

    /**
     * Utility function to fetch the response from the service and extract the
     * title from the XML.
     */
    private static String fetchTitle(String requestUrl) {
        String title = null;
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(requestUrl);
            Node titleNode = doc.getElementsByTagName("Title").item(0);
            title = titleNode.getTextContent();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return title;
    }
}

关于IAM

笔者也有在研究亚马逊的AWS,里边有一套IAM服务,非常方便账户权限的管理,比如我可以创建一个账号,只给它S3的权限,其他服务就访问不了,别人冒用了这个用户的认证信息,也不会造成比S3之外更多的影响。如果能使用IAM用户为联盟API提供认证,会更加方便些,但经过一番调研,结论是,截止到14年3月笔者撰文时,IAM不支持联盟API:
http://stackoverflow.com/questions/9689357/is-it-possible-to-generate-an-aws-access-key-via-iam-for-use-with-the-product-ad

分类
English 技术 演绎作品

Java进程内存分配 – Memory Areas of Java Process

近日学习到了Java内存管理相关的内容,了解了Java内存中Permanent、Old和Young Generation的概念,内容如下文:
Recently I was learning Java memory management and got some ideas about Permanent, Old and Young Generation concepts, which are mentioned in:

http://blog.csdn.net/watchnight/article/details/4987065

文中的第一张示意图让人一目了然,可惜是日文版。用Visio临摹了一下,作了一张英文版以方便大家参考。版权归原作者和Oracle所有。
The first chart in the article is useful however it’s in Japanese. I copy a English version with Visio and share it here. The copyright belongs to the  originator and Oracle.

Memory Areas of Java Process

点击查看原图。
Click to enlarge.

 

分类
English 原创作品 技术 移动互联网

泡面管家Android版开源 – Instant Noodles Master for Android Is Open Souce

专为泡面开发的一键计时器《泡面管家》Android版已开放源代码,并托管于GitHub上。
The One-Tap-Timer for instant noodles, Instant Noodles Master for Android, is now open source on GitHub.

开源项目URL是:
The URL of the open souce project is:

https://github.com/evisong/noodlesmaster

源代码早于2010年已托管在GoogleCode上,于2013年7月迁移至GitHub,原GoogleCode源代码将不再维护。
The souce code is originally hosted on GoogleCode since 2010, and was finally migrated to GitHub on July 2013, since then the copy on GoogleCode will no longer be maintained.