2013-12-29

apexからSimpleDB触ってみる。

例のごとくapexからSimpleDB触ってみる。

 

/**
 * SimpleDBのコモンクラス
 */
public with sharing class SimpleDBCommon {
    /**
     * AccessKey
     */
    public String AWSAccessKeyId = EnvSetting__c.getOrgDefaults().AWSAccessKeyId__c;

    /**
     * SecretKey
     */
    public String AWSSecretKeyId = EnvSetting__c.getOrgDefaults().AWSAccessKeySecret__c;

    /**
     * ドメイン作成
     */
    public String createDomain(String domainName) {
        Map<String, String> params = new Map<String, String>{
            'Action' => 'CreateDomain',
            'AWSAccessKeyId' => this.AWSAccessKeyId,
            'SignatureMethod' => 'HmacSHA256',
            'SignatureVersion' => '2',
            'DomainName' => domainName,
            'Version' => '2009-04-15',
            'Timestamp' => DateTime.now().formatGmt('YYYY-MM-dd') + 'T' + DateTime.now().formatGmt('HH:mm:ssZ')
        };

        params.put('Signature', this.createSignature('POST', 'sdb.amazonaws.com', '/', params));

        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://sdb.amazonaws.com');
        req.setMethod('POST');

        req.setBody(Utility.getSortedParam(params));
        Http http = new Http();
        HTTPResponse res = http.send(req);

        return res.getBody();
    }

    /**
     * ドメイン削除
     */
    public String deleteDomain(String domainName) {
        Map<String, String> params = new Map<String, String>{
            'Action' => 'DeleteDomain',
            'AWSAccessKeyId' => this.AWSAccessKeyId,
            'SignatureMethod' => 'HmacSHA256',
            'SignatureVersion' => '2',
            'DomainName' => domainName,
            'Version' => '2009-04-15',
            'Timestamp' => DateTime.now().formatGmt('YYYY-MM-dd') + 'T' + DateTime.now().formatGmt('HH:mm:ssZ')
        };

        params.put('Signature', this.createSignature('POST', 'sdb.amazonaws.com', '/', params));

        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://sdb.amazonaws.com');
        req.setMethod('POST');

        req.setBody(Utility.getSortedParam(params));
        Http http = new Http();
        HTTPResponse res = http.send(req);

        return res.getBody();
    }

    /**
     * アイテム作成
     */
    public String putAttributes(String domainName, String itemName, Map<String, String> attributes) {
        Map<String, String> params = new Map<String, String>{
            'Action' => 'PutAttributes',
            'AWSAccessKeyId' => this.AWSAccessKeyId,
            'SignatureMethod' => 'HmacSHA256',
            'SignatureVersion' => '2',
            'DomainName' => domainName,
            'Version' => '2009-04-15',
            'Timestamp' => DateTime.now().formatGmt('YYYY-MM-dd') + 'T' + DateTime.now().formatGmt('HH:mm:ssZ'),
            'ItemName' => itemName
        };

        Integer i = 1;
        for (String key : attributes.keySet()) {
        	params.put('Attribute.' + i + '.Name', key);
            params.put('Attribute.' + i + '.Value', attributes.get(key));
            i++;
        }

        params.put('Signature', this.createSignature('POST', 'sdb.amazonaws.com', '/', params));

        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://sdb.amazonaws.com');
        req.setMethod('POST');

        req.setBody(Utility.getSortedParam(params));
        Http http = new Http();
        HTTPResponse res = http.send(req);

        return res.getBody();
    }

    /**
     * クエリ
     */
    public String query(String queryString) {
        Map<String, String> params = new Map<String, String>{
            'Action' => 'Select',
            'AWSAccessKeyId' => this.AWSAccessKeyId,
            'SignatureMethod' => 'HmacSHA256',
            'SignatureVersion' => '2',
            'SelectExpression' => queryString,
            'Version' => '2009-04-15',
            'Timestamp' => DateTime.now().formatGmt('YYYY-MM-dd') + 'T' + DateTime.now().formatGmt('HH:mm:ssZ')
        };

        params.put('Signature', this.createSignature('POST', 'sdb.amazonaws.com', '/', params));

        HttpRequest req = new HttpRequest();
        req.setEndpoint('https://sdb.amazonaws.com');
        req.setMethod('POST');

        req.setBody(Utility.getSortedParam(params));
        Http http = new Http();
        HTTPResponse res = http.send(req);

        return res.getBody();
    }

    private String createSignature(
        String method,
        String hostname,
        String resource,
        Map<String, String> params
    ) {
        String signature = 
            method + Constants.LF +
            hostname.toLowerCase() + Constants.LF +
            resource + Constants.LF +
            Utility.getSortedParam(params);
        System.debug(signature);
        return String.valueOf(EncodingUtil.base64Encode(
            Crypto.generateMac(
                'hmacSHA256', 
                Blob.valueOf(signature),
                Blob.valueOf(this.AWSSecretKeyId)
            )
        ));
    }
}

/**
 * Utilityクラス
 */
public without sharing class Utility {
    public static List getSortedList(Set keys) {
        List sortedList = new List();
        sortedList.addAll(keys);
        sortedList.sort();
        return sortedList;
    }

    /**
     * key=value&...でつないだ文字列を返却
     * @param mapParam 対象文字列=>文字列マップ
     * @return key=value&...でつないだ文字列
     */
    public static String getSortedParam(Map<String,String> mapParam){
        if (mapParam == null || mapParam.keySet().isEmpty()) {
            return '';
        }
        String param = '';
        List sortedKey = getSortedList(mapParam.keySet());
        for(String key: sortedKey){
            param += percentEncodeRfc3986(key) + '=' + percentEncodeRfc3986(mapParam.get(key)) + '&';
        }
        return param.substring(0,param.length() - 1);
    }

    public static String percentEncodeRfc3986(String s) {
        return EncodingUtil.urlEncode(s, 'UTF-8')
                    .replace('+', '%20')
                      .replace('*', '%2A')    
                      .replace('%7E', '~');
    }
}

 

signature生成はSignature Version 2なので簡単っす。

 

あと、simpleDBは1GBまで無料とか結構安いみたいなので

S3オブジェクトに対する情報付与のためのテーブルとかそういうのに気軽に使えそう。

スナップショット系にもいけるかなー。

http://aws.amazon.com/jp/simpledb/pricing/

 

ただし、ベータ版だからエンタープライズ分野にはまだ着手しずらいかも。

dynamoもRDSよりは安いので、エンタープライズ系だとdynamo使った方が色々と無難な気がします。

このエントリーをはてなブックマークに追加