com.xeiam.xchange.mtgox.v2.service.streaming.SocketMessageFactory.java Source code

Java tutorial

Introduction

Here is the source code for com.xeiam.xchange.mtgox.v2.service.streaming.SocketMessageFactory.java

Source

/**
 * Copyright (C) 2012 - 2013 Xeiam LLC http://xeiam.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is furnished to do
 * so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.xeiam.xchange.mtgox.v2.service.streaming;

import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

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

import org.joda.money.BigMoney;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xeiam.xchange.dto.Order;
import com.xeiam.xchange.mtgox.MtGoxUtils;
import com.xeiam.xchange.utils.Base64;

/**
 * @author macarse
 */
public class SocketMessageFactory {

    private final String apiKey;
    private final String apiSecret;

    /**
     * Constructor
     * 
     * @param apiKey
     * @param apiSecret
     */
    public SocketMessageFactory(String apiKey, String apiSecret) {

        if (apiKey == null || apiSecret == null || apiKey.length() == 0 || apiSecret.length() == 0) {
            throw new IllegalArgumentException("mtgox api key and/or secret is missing");
        }

        if (apiKey == null || apiSecret == null || apiKey.length() == 0 || apiSecret.length() == 0) {
            throw new IllegalArgumentException("mtgox api key and or secret is missing");
        }

        this.apiKey = apiKey;
        this.apiSecret = apiSecret;
    }

    public String unsubscribeToChannel(String channel) throws JsonProcessingException {

        HashMap<String, String> map = new HashMap<String, String>(2);
        map.put("op", "unsubscribe");
        map.put("channel", channel);

        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(map);

    }

    public String subscribeWithChannel(String channel) throws JsonProcessingException {

        HashMap<String, String> map = new HashMap<String, String>(2);
        map.put("op", "mtgox.subscribe");
        map.put("channel", channel);

        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(map);
    }

    public String subscribeWithType(String type) throws JsonProcessingException {

        HashMap<String, String> map = new HashMap<String, String>(2);
        map.put("op", "mtgox.subscribe");
        map.put("type", type);

        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(map);
    }

    public String subscribeWithKey(String key) throws JsonProcessingException {

        HashMap<String, String> map = new HashMap<String, String>(2);
        map.put("op", "mtgox.subscribe");
        map.put("key", key);

        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(map);
    }

    public String cancelOrder(String oid) throws UnsupportedEncodingException, JsonProcessingException {

        HashMap<String, String> params = new HashMap<String, String>(1);
        params.put("oid", oid);

        String reqId = String.format("order_cancel:%s", oid);
        return signedCall("order/cancel", params, reqId);
    }

    public String addOrder(Order.OrderType orderType, BigMoney price, BigDecimal amount)
            throws UnsupportedEncodingException, JsonProcessingException {

        String typeStr = Order.OrderType.ASK == orderType ? "ask" : "bid";
        String priceStr = MtGoxUtils.getPriceString(price);
        String amountStr = MtGoxUtils.getAmountString(amount);

        HashMap<String, String> params = new HashMap<String, String>(3);
        params.put("type", typeStr);
        params.put("amount_int", amountStr);

        // if price <= 0, it's a market order
        if (price.isGreaterThan(BigMoney.zero(price.getCurrencyUnit()))) {
            params.put("price_int", priceStr);
        }

        String reqId = String.format("order_add:%s:%s:%s", typeStr, priceStr, amountStr);
        return signedCall("order/add", params, reqId);
    }

    public String idKey() throws JsonProcessingException, UnsupportedEncodingException {

        return signedCall("private/idkey", new HashMap<String, String>(), "idkey");
    }

    public String privateOrders() throws UnsupportedEncodingException, JsonProcessingException {

        return signedCall("private/orders", new HashMap<String, String>(), "orders");
    }

    public String privateInfo() throws UnsupportedEncodingException, JsonProcessingException {

        return signedCall("private/info", new HashMap<String, String>(), "info");
    }

    private String signedCall(String endPoint, Map<String, String> params, String reqId)
            throws JsonProcessingException, UnsupportedEncodingException {

        long nonce = MtGoxUtils.getNonce();

        HashMap<String, Object> call = new HashMap<String, Object>(6);
        call.put("id", reqId);
        call.put("call", endPoint);
        call.put("nonce", nonce);
        call.put("params", params);

        ObjectMapper mapper = new ObjectMapper();
        String callString = mapper.writeValueAsString(call);
        String signedCall = null;

        try {
            byte[] bsecret = Base64.decode(this.apiSecret);
            SecretKeySpec spec = new SecretKeySpec(bsecret, "HmacSHA512");
            Mac mac = Mac.getInstance("HmacSHA512");
            mac.init(spec);

            byte[] bsig = mac.doFinal(callString.getBytes());
            byte[] keyB = fromHexString(this.apiKey.replaceAll("-", ""));
            byte[] callB = callString.getBytes();

            byte[] c = new byte[bsig.length + keyB.length + callB.length];
            System.arraycopy(keyB, 0, c, 0, keyB.length);
            System.arraycopy(bsig, 0, c, keyB.length, bsig.length);
            System.arraycopy(callB, 0, c, keyB.length + bsig.length, callB.length);

            signedCall = Base64.encodeBytes(c);

        } catch (Exception e) {
            System.out.println("e!: " + e);

        }

        HashMap<String, String> msg = new HashMap<String, String>(4);
        msg.put("op", "call");
        msg.put("call", signedCall);
        msg.put("id", reqId);
        msg.put("context", "mtgox.com");

        mapper = new ObjectMapper();
        return mapper.writeValueAsString(msg);
    }

    private static byte[] fromHexString(String hex) {

        ByteArrayOutputStream bas = new ByteArrayOutputStream();
        for (int i = 0; i < hex.length(); i += 2) {
            int b = Integer.parseInt(hex.substring(i, i + 2), 16);
            bas.write(b);
        }

        return bas.toByteArray();
    }

}