CloudStack API URLをJavaで生成する

## CloudStack API URLをJavaで生成するコード
Androidから使いたいため、Base64.encodeBase64String();は利用しないやり方です。
お勉強中なので確認用出力コードもそのまま記載、自分と同じように勉強中の方のお役に立てば幸いです。


```java
import java.net.URLEncoder;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.util.TreeMap;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.Mac;
import android.util.Base64;  //←Androidから使う場合はこちらを利用
//import java.util.Base64;　　 ←通常のJavaから使う場合はこちらを利用

public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
            
        String queryString = "";
        String host = "http://<yourCloudStackHost>/client/api";
　　　　 String apiUrl = "";
        String apiKey = "yourApiKey";
        Key secKey = new SecretKeySpec("yourSecretKey".getBytes(),"HmacSHA1");
        TreeMap<String,String> params = new TreeMap<>();
        params.put("response","json");
        params.put("command","listZones");
        params.put("apikey",apiKey);
        
        for(String key:params.keySet()){
            if(queryString.isEmpty()){
                queryString = key + "=" + params.get(key);
            }else{
                queryString = queryString + "&" + key + "=" + params.get(key);
            }
            //System.out.println(key + "=" + params.get(key));
            System.out.println(queryString);
        }
        String queryStringLow = queryString.toLowerCase();
        System.out.println(queryStringLow);
        //シークレットキーを利用して、HMAC SHA1でハッシュする
        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(secKey);
        byte[] digest = mac.doFinal(queryStringLow.getBytes());

        //BASE64エンコード
        String b64 = Base64.getEncoder().encodeToString(digest);

        //URLエンコード
        String signature = URLEncoder.encode(b64);
        signature = signature.replaceAll("%0A",""); //改行コード除去

　　　　//URL生成
　　　　apiUrl = host + "?" + queryString + "&signature=" + signature;
        //デバッグ用
        System.out.println(digest);
        System.out.println(b64);
        System.out.println(signature);
        System.out.println(queryString + "&signature=" + signature);
        System.out.println(apiUrl);
                
    }
}
```
apiURLに、

```
http://<yourCloudStackHost>/client/api？apikey=<yourApiKey>&command=listZones&response=json&signature=<yourSignature>
```
と入ってくるはずなので、こちらをコピーしターミナル等でアクセスしてみます。

```bash
curl -s 'http://<yourCloudStackHost>/client/api？apikey=<yourApiKey>&command=listZones&response=json&signature=<yourSignature>' | jq -C
```
応答結果

```bash
{
  "listzonesresponse": {
    "count": 3,
    "zone": [
      {
        "id": "e8ebfccb-eb38-43ed-8abf-XXXX",
        "name": "weber",
        "networktype": "Advanced",
        "securitygroupsenabled": false,
        "allocationstate": "Enabled",
        "zonetoken": "42101a12-6299-32c7-a324-XXXX",
        "dhcpprovider": "VirtualRouter",
        "localstorageenabled": true,
        "tags": []
      },
      {
        "id": "95c8746d-57b3-421f-9375-XXXX",
        "name": "lux",
        "networktype": "Advanced",
        "securitygroupsenabled": false,
        "allocationstate": "Enabled",
        "zonetoken": "de9e9a4f-696d-39f4-bb3e-XXXX",
        "dhcpprovider": "VirtualRouter",
        "localstorageenabled": true,
        "tags": []
      },
      {
        "id": "f4583787-7bff-461a-b026-XXXX",
        "name": "farad",
        "networktype": "Advanced",
        "securitygroupsenabled": false,
        "allocationstate": "Enabled",
        "zonetoken": "a53d8e78-3c77-3352-8a04-XXXX",
        "dhcpprovider": "VirtualRouter",
        "localstorageenabled": true,
        "tags": []
      }
    ]
  }
}
```
signature等が間違っている場合の応答結果

```bash
{
  "listzonesresponse": {
    "errorcode": 401,
    "errortext": "unable to verify user credentials and/or request signature"
  }
}
```