Androidアプリ内にてPAY.JPのカードトークン作成

AndroidアプリにPAY.JPのカードトークン取得機能を組み込む必要があったのですが、PAY.JP側のライブラリではAndroidに対応していませんでした。

Java用ライブラリは用意されているのですが、下記ランタイムエラーが発生するためAndroidでは利用できません。
Caused by: java.lang.NoClassDefFoundError: javax.xml.bind.DatatypeConverter
at jp.pay.net.LivePayjpResponseGetter.getHeaders(LivePayjpResponseGetter.java:85)

既存プロジェクトではvolleyを使っていたので、直接PAY.JPのRestAPIにリクエストを投げることで対応するに至りました。

以下サンプルとなります。

final String apiKey = "pk_test_123456789012345678901234";//PAY.JPの公開APIキー
String url = "https://api.pay.jp/v1/tokens";
Map<String,String> params = new HashMap<>();
params.put("card[number]",number);
params.put("card[name]",name);
params.put("card[cvc]",cvc);
params.put("card[exp_month]",expMonth);
params.put("card[exp_year]",expYear);
JsonObjectRequestHashMapPost request = new JsonObjectRequestHashMapPost(Request.Method.POST, url, params,
        new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject jsonObject) {
                try{
                    //トークン取得して後続処理を呼ぶ
                    token = jsonObject.getString("id");
                }catch(Exception e){
                    //正常にトークンが発行されなかった
                    e.printStackTrace();
                }
            }
        },
        new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                //エラー処理
                switch(volleyError.networkResponse.statusCode){
                    case 400:
                        //不正なパラメータなどのリクエストエラー
                        break;
                    case 401:
                        //APIキーの認証エラー
                        break;
                    case 402:
                        //カード認証・支払いエラー
                        break;
                    case 500:
                        //PAY.JPや決済ネットワークでの障害
                        break;
                    default:
                }
            }
        }
){
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> headers = super.getHeaders();
        // Add BASIC AUTH HEADER
        Map<String, String> newHeaders = new HashMap<String, String>();
        newHeaders.putAll(headers);
        // APIキーにコロンを追加
        String userString = apiKey+":";
        // APIキーをBase64でエンコード
        String user = String.format("Basic %s", Base64.encodeToString(userString.getBytes(), Base64.URL_SAFE| Base64.NO_WRAP));
        newHeaders.put("Authorization", user);
        return newHeaders;
    }
};
//Queueに追加(JSON取得処理)
RequestQueue mQueue = Volley.newRequestQueue(this);
mQueue.add(request);

ポイントはオーバーライドしているpublic Map<String, String> getHeadersで、コロン(:)を追加したapiキーをBase64でエンコードし、HttpリクエストヘッダーのAuthorizationとして追加するところ。

 

ちなみにJsonObjectRequestHashMapPostはその名の通り、HashMapをPostするためにRequestを拡張したクラスです。こちらも参考までに。

public class JsonObjectRequestHashMapPost extends Request<JSONObject> {
    private Listener<JSONObject> listener;
    private Map<String, String> params;

    public JsonObjectRequestHashMapPost(String url, Map<String, String> params,
                         Listener<JSONObject> responseListener, ErrorListener errorListener) {
        super(Method.GET, url, errorListener);
        this.listener = responseListener;
        this.params = params;
    }

    public JsonObjectRequestHashMapPost(int method, String url, Map<String, String> params,
                         Listener<JSONObject> responseListener, ErrorListener errorListener) {
        super(method, url, errorListener);
        this.listener = responseListener;
        this.params = params;
    }

    protected Map<String, String> getParams()
            throws com.android.volley.AuthFailureError {
        return params;
    };

    @Override
    protected Response<JSONObject> parseNetworkResponse(NetworkResponse response) {
        try {
            String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
            return Response.success(new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JSONException je) {
            return Response.error(new ParseError(je));
        }
    }

    @Override
    protected void deliverResponse(JSONObject response) {
        listener.onResponse(response);
    }
}

参考

ディスク容量不足の時の調査

Linuxサーバーでディスク容量が逼迫し始めたとき、どのディレクトリが容量を食ってるか調査する手段。

しょっちゅう使う事がないので、いざというときに忘れているから覚え書きとして...。

#du -h –max-depth=1 /

とすると、ルートディレクトリ配下のディレクトリ毎にどれだけ容量を食ってるかが表示される。

#du -h –max-depth=1 /var

とかで下層を掘っていくことが可能。