/*
DConnectSDK.java
Copyright (c) 2016 NTT DOCOMO,INC.
Released under the MIT license
http://opensource.org/licenses/mit-license.php
*/
package org.deviceconnect.message;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import org.deviceconnect.message.entity.Entity;
import org.deviceconnect.profile.AuthorizationProfileConstants;
import org.deviceconnect.profile.AvailabilityProfileConstants;
import org.deviceconnect.profile.ServiceDiscoveryProfileConstants;
import org.deviceconnect.profile.ServiceInformationProfileConstants;
import org.deviceconnect.utils.HmacUtils;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Device Connect Managerへのアクセスを行うクラス.
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* // sdkは、使い回すこと。
* final DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
*
* String[] scopes = {
* "serviceDiscovery",
* "serviceInformation",
* "battery"
* };
*
* DConnectResponseMessage response = sdk.authorization("SampleApp", scopes, new OnAuthorizationListener() {
* <code>@</code>Override
* public void onResponse(String clientId, String accessToken) {
* // Local OAuthの認証に成功
* // 必要に応じて、アクセストークンはファイルなどに保存して使いまわすこと。
* // 取得したアクセストークンをSDKに設定
* sdk.setAccessToken(accessToken);
* }
* <code>@</code>Override
* public void onError(int errorCode, String errorMessage) {
* // Local OAuthの認証に失敗
* }
* });
*
* // 省略・・・
*
* DConnectSDK.URIBuilder builder = sdk.createURIBuilder();
* builder.setProfile("battery");
* builder.setServiceId(serviceId);
* sdk.get(builder.build(), new OnResponseListener() {
* <code>@</code>Override
* public void onResponse(DConnectResponseMessage response) {
* if (response.getResult() == DConnectMessage.RESULT_OK) {
* float level = response.getFloat("level");
* } else {
* // エラー
* }
* }
* });
* </pre>
* </div>
* @author NTT DOCOMO, INC.
*/
public abstract class DConnectSDK {
/**
* Device Connect Manager起動確認用ActivityへのComponentName.
*/
private static final ComponentName MANAGER_LAUNCH_ACTIVITY = new ComponentName("org.deviceconnect.android.manager",
"org.deviceconnect.android.manager.DConnectLaunchActivity");
/**
* HMACを生成するためのキーのサイズを定義する.
*/
private static final int HMAC_KEY_BYTES = 16;
/**
* nonceの値に格納する文字列のサイズを定義する.
*/
private static final int NONCE_BYTES = 16;
/**
* メソッド.
*/
enum Method {
/**
* GETメソッド.
*/
GET("GET"),
/**
* PUTメソッド.
*/
PUT("PUT"),
/**
* POSTメソッド.
*/
POST("POST"),
/**
* DELETEメソッド.
*/
DELETE("DELETE");
String mValue;
Method(final String value) {
mValue = value;
}
String getValue() {
return mValue;
}
}
/**
* Device Connect Managerへのホスト名.
*/
private String mHost = "localhost";
/**
* Device Connect Managerのポート番号.
*/
private int mPort = 4035;
/**
* アプリケーションのオリジン.
*/
private String mOrigin;
/**
* SSL使用フラグ.
* <p>
* trueの場合はSSLを使用する。<br>
* falseの場合にはSSLを使用しない。
* </p>
*/
private boolean mSSL;
/**
* アクセストークン.
*/
private String mAccessToken;
/**
* サーバを識別するHMACキー.
*/
private String mHmacKey;
/**
* サーバの妥当性確認フラグ.
* <p>
* truの場合は、Device Connect Managerの妥当性を確認する。<br>
* falseの場合には、妥当性の確認は行わない。
* </p>
*/
private boolean mEnabledAntiSpoofing;
/**
* 通信を行うスレッド.
*/
private ExecutorService mExecutorService = Executors.newFixedThreadPool(4);
DConnectSDK() {}
/**
* Device Connect Managerのホスト名を取得する.
* <p>
* デフォルトではlocalhostが設定してあります。
* </p>
* @return Device Connect Managerのホスト名
*/
public String getHost() {
return mHost;
}
/**
* Device Connect Managerのホスト名を設定する.
* <p>
* デフォルトではlocalhostが設定してあります。<br>
* 別のホストにあるDevice Connect Managerにアクセスする場合には、設定をしなおしてください。<br>
* </p>
* @param host Device Connect Managerのホスト名
* @throws NullPointerException hostに{@code null}が指定された場合に発生
* @throws IllegalArgumentException hostに空文字などが指定された場合に発生
*/
public void setHost(final String host) {
if (host == null) {
throw new NullPointerException("host is null.");
}
if (host.isEmpty()) {
throw new IllegalArgumentException("host is empty.");
}
mHost = host;
}
/**
* Device Connect Managerのポート番号を取得する.
* @return Device Connect Managerのポート番号
*/
public int getPort() {
return mPort;
}
/**
* Device Connect Managerのポート番号を設定する.
* <p>
* デフォルトでは、4035が設定してあります。
* </p>
* @param port Device Connect Managerのポート番号
* @throws IllegalArgumentException portの値が0以下または、65536以上の場合に発生
*/
public void setPort(final int port) {
if (port < 0 || port > 65535) {
throw new IllegalArgumentException("port is invalid. port=" + port);
}
mPort = port;
}
/**
* アプリケーションのOriginを取得する.
* @return アプリケーションのOrigin
*/
public String getOrigin() {
return mOrigin;
}
/**
* アプリケーションのOriginを設定する.
* <p>
* アプリケーションのOriginを変更したい場合には、このメソッドで変更します。<br>
* デフォルトでは、アプリケーションのパッケージ名が設定してあります。
* </p>
* @param origin アプリケーションのOrigin
* @throws NullPointerException originに{@code null}が指定された場合に発生
* @throws IllegalArgumentException originに空文字などが指定された場合に発生
*/
public void setOrigin(final String origin) {
if (origin == null) {
throw new NullPointerException("origin is null.");
}
if (origin.isEmpty()) {
throw new IllegalArgumentException("origin is empty.");
}
mOrigin = origin;
}
/**
* SSL使用フラグを取得する.
*
* @return trueの場合はSSLを使用する、それ以外の場合は使用しない。
*/
public boolean isSSL() {
return mSSL;
}
/**
* SSL使用フラグを設定する.
*
* @param SSL trueの場合はSSLを使用する、それ以外の場合は使用しない。
*/
public void setSSL(final boolean SSL) {
mSSL = SSL;
}
/**
* アクセストークンを取得する.
* <p>
* 設定されていない場合には{@code null}を返却します。<br>
* デフォルトでは、何も設定されていないので{@code null}を返却します。
* </p>
* @return アクセストークン
*/
public String getAccessToken() {
return mAccessToken;
}
/**
* アクセストークンを設定する.
* <p>
* アクセストークンを取得する方法は、{@link #authorization(String, String[])}を参照してください。
* </p>
* @param accessToken アクセストークン
* @throws NullPointerException accessTokenに{@code null}が指定された場合に発生
* @throws IllegalArgumentException accessTokenに空文字などが指定された場合に発生
*/
public void setAccessToken(final String accessToken) {
if (accessToken == null) {
throw new NullPointerException("accessToken is null.");
}
if (accessToken.isEmpty()) {
throw new IllegalArgumentException("accessToken is empty.");
}
mAccessToken = accessToken;
}
/**
* イベント受信用のWebSocketを Device Connect Managerへ接続する.
* <p>
* すでに接続されている場合には、処理は行わずに無視します。<br>
* この関数でWebSocketを開いたあとは、必ず{@link #disconnectWebSocket()}を呼び出して、WebSocketを切断してください。
* </p>
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
* sdk.connectWebSocket(new OnWebSocketListener() {
* <code>@</code>Override
* public void onOpen() {
* }
*
* <code>@</code>Override
* void onClose() {
* }
*
* <code>@</code>Override
* void onError(Exception e) {
* }
* });
* </pre>
* </div>
* @param listener WebSocket状態通知リスナー
*/
public abstract void connectWebSocket(final OnWebSocketListener listener);
/**
* イベント受信用のWebSocketを切断する.
* <p>
* WebSocketが接続されていない場合には、処理を無視します。
* </p>
*/
public abstract void disconnectWebSocket();
/**
* イベント受信用のWebSocketがDevice Connect Managerと接続されているかを確認する.
* @return 接続されている場合にはtrue、それ以外はfalse
*/
public abstract boolean isConnectedWebSocket();
/**
* イベントを登録する.
* <p>
* イベントの登録成功・失敗やイベントメッセージは、第2引数のlistenerに通知されます。
* </p>
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
* DConnectSDK.URIBuilder builder = sdk.createURIBuilder();
* builder.setProfile("battery");
* builder.setServiceId("serviceId");
* sdk.addEventListener(builder.build(), new OnEventListener() {
* <code>@</code>Override
* public void onResponse(DConnectResponseMessage response) {
* if (response.getResult() == DConnectMessage.RESULT_OK) {
* // イベント登録成功
* } else {
* // イベント登録失敗
* }
* }
* <code>@</code>Override
* public void onMessage(DConnectEventMessage message) {
* // イベントの通知
* }
* });
* </pre>
* </div>
* @param uri 登録するイベントへのURI
* @param listener イベント通知リスナー
*/
public void addEventListener(final String uri, final OnEventListener listener) {
addEventListener(Uri.parse(uri), listener);
}
/**
* イベントを登録する.
* @param uri 登録するイベントへのURI
* @param listener イベント通知リスナー
*/
public abstract void addEventListener(final Uri uri, final OnEventListener listener);
/**
* イベントを解除する.
* @param uri 削除するイベントへのURI
*/
public void removeEventListener(final String uri) {
removeEventListener(Uri.parse(uri));
}
/**
* イベントを削除する.
* @param uri 削除するイベントへのURI
*/
public abstract void removeEventListener(final Uri uri);
/**
* サーバからのレスポンス受信時にサーバの認証を行うかどうかを設定する.
* <p>
* サーバ認証を行うためのHMACのキーをDConnectSDKの内部で保持するために、
* 別のDConnectSDKのインスタンスを作成した場合には、もう一度、{@link #startManager(Context)}
* を呼び出して、HMACのキーを生成し直す必要があります。
* </p>
* @param enable サーバの認証を行う場合はtrue、そうでない場合はfalse
*/
public void setAntiSpoofing(final boolean enable) {
mEnabledAntiSpoofing = enable;
}
/**
* サーバからのレスポンス受信時にサーバの認証を行うかどうかのフラグを取得する.
*
* @return サーバの認証を行う場合はtrue、そうでない場合はfalse
*/
public boolean isEnabledAntiSpoofing() {
return mEnabledAntiSpoofing;
};
/**
* Device Connect Managerを起動する.
* <p>
* Device Connect Managerを起動するために一瞬透明なActivityが起動するので、
* Activityが一時停止されることに注意する必要があります。
* </p>
* <p>
* Device Connect Managerの設定において、外部からの自動起動/終了が無効の場合には、
* Device Connect Managerの起動画面が表示されます。
* </p>
* <p>
* {@link #setAntiSpoofing(boolean)}に{@code true}が設定されている場合には、
* 内部でDevice Connect Managerの妥当性を確認するためのHMACのキーを生成し、Device Connect Managerに渡します。<br>
* このHMACのキーを元にDevice Connect ManagerはレスポンスにHMACを付加して返却してきます。<br>
* {@link #get(String, OnResponseListener)}などの処理中で、レスポンスからHMACを取得して、
* 起動した時に生成したHMACのキーから同じHMACが生成できるかを確認します。<br>
* 同じHMACが生成できない場合には、このメソッドで起動したDevice Connect Managerからのレスポンスとします。<br>
* DConnectSDKが違う場合には、HMACのキーが異なるので、Device Connect Managerの妥当性を確認する場合には、
* DConnectSDKのインスタンスは使い回す必要があります。
* </p>
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
* DConnectResponseMessage response = sdk.availability();
* if (response.getResult() == DConnectMessage.RESULT_ERROR) {
* sdk.startManager(context);
* }
* </pre>
* </div>
* @param context コンテキスト
*/
public void startManager(final Context context) {
startManager(context, "gotapi://start/server");
}
/**
* Device Connect Manager起動確認用のActivityを起動する.
* @param context コンテキスト
*/
public void startManagerWithActivity(final Context context) {
startManager(context, "gotapi://start/activity");
}
/**
* Device Connect Managerの起動処理を行う。
* @param context コンテキスト
* @param uri 起動URI
*/
private void startManager(final Context context, final String uri) {
mHmacKey = isEnabledAntiSpoofing() ? generateRandom(HMAC_KEY_BYTES) : "";
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setComponent(MANAGER_LAUNCH_ACTIVITY);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(uri + "?origin=" + mOrigin + "&key=" + mHmacKey));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
/**
* 送れてきたHMACが正しいか確認を行う.
* <p>
* origin、nonceとmHmacKeyからHMACを生成して、Device Connect Managerの返り値と一致するかを確認します。<br>
* 値が一致する場合には、正しいDevice Connect Managerから返り値と認識します。
* </p>
* @param nonce HMACを生成するために使用したシード
* @param hmac Device Connect Managerから送られてきたHMAC
* @return HMACが一致する場合にはtrue、それ以外はfalse
*/
private boolean checkHmac(final String nonce, final String hmac) {
String hmacKey = mHmacKey;
if (hmacKey == null || hmacKey.isEmpty()) {
return true;
}
if (hmac == null) {
return false;
}
String expectedHmac = HmacUtils.generateHmac(getOrigin(), nonce, hmacKey);
return hmac.equals(expectedHmac);
}
/**
* ランダムな文字列を生成する.
* @param byteSize 文字数
* @return ランダムな文字列
*/
private String generateRandom(final int byteSize) {
StringBuilder builder = new StringBuilder();
Random random = new Random();
for (int i = 0; i < byteSize; i++) {
builder.append(Integer.toHexString(random.nextInt(255)));
}
return builder.toString();
}
/**
* Device Connect Managerを停止する.
* <p>
* Device Connect Managerを停止するために一瞬透明なActivityが起動するので、
* Activityが一時停止されることに注意すること。
* </p>
* <p>
* Device Connect Managerの設定において、外部からの自動起動/終了が無効の場合には、
* Device Connect Managerの停止画面が表示されます。
* </p>
* @param context コンテキスト
*/
public void stopManager(final Context context) {
stopManager(context, "gotapi://stop/server");
}
/**
* Device Connect Manager停止確認用のActivityを起動する.
* @param context コンテキスト
*/
public void stopManagerWithActivity(final Context context) {
stopManager(context, "gotapi://stop/activity");
}
/**
* Device Connect Managerを停止する.
* @param context コンテキスト
* @param uri Device Connect Managerの停止URI
*/
private void stopManager(final Context context, final String uri) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setComponent(MANAGER_LAUNCH_ACTIVITY);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.setData(Uri.parse(uri));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
/**
* Device Connect Managerとの通信を行う.
* <p>
* 同期的に処理を行い、Device Connect Managerとの通信結果を返却する。<br>
* レスポンスにはnullを返さないようにすること。
* </p>
* @param method メソッド
* @param uri アクセス先のURI
* @param headers リクエストに追加するヘッダー
* @param body リクエストに追加するボディデータ
* @return レスポンス
*/
protected abstract DConnectResponseMessage sendRequest(final Method method, final Uri uri, final Map<String, String> headers, final Entity body);
/**
* Device Connect Managerとの通信を行う.
* <p>
* {@link #isEnabledAntiSpoofing()}がtrueの場合には、HMACの確認を行い不正なサーバにアクセスしていないか確認を行います。<br>
* ただし、HMACを作成するためのキーは、DConnectSDKが保持しているので、別のDConnectSDKのインスタンスを使用した場合には、エラーになる。
* </p>
* @param method メソッド
* @param uri アクセス先のURI
* @param headers リクエストに追加するヘッダー
* @param body リクエストに追加するボディデータ
* @return レスポンス
*/
private DConnectResponseMessage sendRequestInternal(final Method method, final Uri uri, final Map<String, String> headers, final Entity body) {
if (isEnabledAntiSpoofing()) {
String nonce = generateRandom(NONCE_BYTES);
StringBuilder u = new StringBuilder();
u.append(uri.toString());
u.append((uri.getQuery() == null) ? "?" : "&");
u.append("nonce=");
u.append(nonce);
DConnectResponseMessage response = sendRequest(method, Uri.parse(u.toString()), headers, body);
if (!checkHmac(nonce, response.getString("hmac"))) {
DConnectResponseMessage msg = new DConnectResponseMessage(DConnectMessage.RESULT_ERROR);
msg.setErrorCode(DConnectMessage.ErrorCode.INVALID_SERVER.getCode());
msg.setErrorMessage(DConnectMessage.ErrorCode.INVALID_SERVER.toString());
return msg;
}
return response;
} else {
return sendRequest(method, uri, headers, body);
}
}
/**
* URIBuilderを生成する.
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
* DConnectSDK.URIBuilder builder = sdk.createURIBuilder();
* builder.setProfile("battery");
* builder.setServiceId("serviceId");
* </pre>
* </div>
* @return URIBuilderのインスタンス
*/
public URIBuilder createURIBuilder() {
return new URIBuilder();
}
/**
* GETメソッドで指定したURIにアクセスし、レスポンスを取得する.
* <p>
* Device Connect Managerに同期的にアクセスを行う為にUIスレッドなどから呼び出すとエラーになります。<br>
* 非同期的に呼び出したい場合には、{@link #get(String, OnResponseListener)}を使用してください。
* </p>
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
* DConnectResponseMessage response = sdk.get("http://localhost:4035/gotapi/availability");
* if (response.getResult() == DConnectMessage.RESULT_OK) {
* // Device Connect Manager起動中
* }
* </pre>
* </div>
* @param uri アクセス先のURI
* @return レスポンス
*/
public DConnectResponseMessage get(final String uri) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
return get(Uri.parse(uri));
}
/**
* GETメソッドで指定したURIにアクセスし、レスポンスを取得する.
* <p>
* Device Connect Managerに同期的にアクセスを行う為にUIスレッドなどから呼び出すとエラーになります。<br>
* 非同期的に呼び出したい場合には、{@link #get(String, OnResponseListener)}を使用してください。
* </p>
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
*
* DConnectSDK.URIBuilder builder = sdk.createURIBuilder();
* builder.setProfile("availability");
*
* DConnectResponseMessage response = sdk.get(builder.build());
* if (response.getResult() == DConnectMessage.RESULT_OK) {
* // Device Connect Manager起動中
* }
* </pre>
* </div>
* @param uri アクセス先のURI
* @return レスポンス
*/
public DConnectResponseMessage get(final Uri uri) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
return sendRequestInternal(Method.GET, uri, null, null);
}
/**
* 非同期にGETメソッドで指定したURIにアクセスし、レスポンスをリスナーに通知する.
* @param uri アクセス先のURI
* @param listener レスポンスを通知するリスナー
*/
public void get(final String uri, final OnResponseListener listener) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
get(Uri.parse(uri), listener);
}
/**
* 非同期にGETメソッドで指定したURIにアクセスし、レスポンスをリスナーに通知する.
* @param uri アクセス先のURI
* @param listener レスポンスを通知するリスナー
*/
public void get(final Uri uri, final OnResponseListener listener) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
mExecutorService.submit(new Runnable() {
@Override
public void run() {
DConnectResponseMessage response = get(uri);
if (listener != null) {
listener.onResponse(response);
}
}
});
}
/**
* PUTメソッドで指定したURIにアクセスし、レスポンスを取得する.
* @param uri アクセス先のURI
* @param data 送信するボディデータ
* @return レスポンス
*/
public DConnectResponseMessage put(final String uri, final Entity data) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
return put(Uri.parse(uri), data);
}
/**
* PUTメソッドで指定したURIにアクセスし、レスポンスを取得する.
* @param uri アクセス先のURI
* @param data 送信するボディデータ
* @return レスポンス
*/
public DConnectResponseMessage put(final Uri uri, final Entity data) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
return sendRequestInternal(Method.PUT, uri, null, data);
}
/**
* 非同期にPUTメソッドで指定したURIにアクセスし、レスポンスをリスナーに通知する.
* @param uri アクセス先のURI
* @param data 送信するボディデータ
* @param listener レスポンスを通知するリスナー
*/
public void put(final String uri, final Entity data, final OnResponseListener listener) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
put(Uri.parse(uri), data, listener);
}
/**
* 非同期にPUTメソッドで指定したURIにアクセスし、レスポンスをリスナーに通知する.
* @param uri アクセス先のURI
* @param data 送信するボディデータ
* @param listener レスポンスを通知するリスナー
*/
public void put(final Uri uri, final Entity data, final OnResponseListener listener) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
mExecutorService.submit(new Runnable() {
@Override
public void run() {
DConnectResponseMessage result = put(uri, data);
if (listener != null) {
listener.onResponse(result);
}
}
});
}
/**
* POSTメソッドで指定したURIにアクセスし、レスポンスを取得する.
* <p>
* 引数のdataに{@link org.deviceconnect.message.entity.MultipartEntity MultipartEntity}を渡した場合には、ボディにマルチパートを格納してDevice Connect Managerに送信する。<br>
* {@link org.deviceconnect.message.entity.MultipartEntity MultipartEntity}には、{@link org.deviceconnect.message.entity.BinaryEntity BinaryEntity}、
* {@link org.deviceconnect.message.entity.FileEntity FileEntity}、{@link org.deviceconnect.message.entity.StringEntity StringEntity}をマルチパートに格納することができます。
* </p>
* <p>
* 引数のdataに{@link org.deviceconnect.message.entity.StringEntity StringEntity}を渡した場合には、ボディに文字列を入れてDevice Connect Managerに送信する。
* </p>
* <p>
* 引数のdataに{@link org.deviceconnect.message.entity.BinaryEntity BinaryEntity}を渡した場合には、ボディにバイナリを入れてDevice Connect Managerに送信する。
* </p>
* <p>
* dataに{@code null}が指定された場合には、データは何もつけずにDevice Connect Managerにアクセスする。
* </p>
* @param uri アクセス先のURI
* @param data 送信するボディデータ
* @return レスポンス
*/
public DConnectResponseMessage post(final String uri, final Entity data) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
return post(Uri.parse(uri), data);
}
/**
* POSTメソッドで指定したURIにアクセスし、レスポンスを取得する.
* <p>
* 引数のdataに{@link org.deviceconnect.message.entity.MultipartEntity MultipartEntity}を渡した場合には、ボディにマルチパートを格納してDevice Connect Managerに送信する。<br>
* {@link org.deviceconnect.message.entity.MultipartEntity MultipartEntity}には、{@link org.deviceconnect.message.entity.BinaryEntity BinaryEntity}、
* {@link org.deviceconnect.message.entity.FileEntity FileEntity}、{@link org.deviceconnect.message.entity.StringEntity StringEntity}をマルチパートに格納することができます。
* </p>
* <p>
* 引数のdataに{@link org.deviceconnect.message.entity.StringEntity StringEntity}を渡した場合には、ボディに文字列を入れてDevice Connect Managerに送信する。
* </p>
* <p>
* 引数のdataに{@link org.deviceconnect.message.entity.BinaryEntity BinaryEntity}を渡した場合には、ボディにバイナリを入れてDevice Connect Managerに送信する。
* </p>
* <p>
* dataに{@code null}が指定された場合には、データは何もつけずにDevice Connect Managerにアクセスする。
* </p>
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード1</span>
* <pre>
* MultipartEntity dataMap = new MultipartEntity();
* dataMap.add("mode", "scales");
* dataMap.add("data", new FileEntity(new File("/data/data/0/org.mycompany.sample/files/sample.png")));
*
* DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
* DConnectSDK.URIBuilder builder = sdk.createURIBuilder();
* builder.setProfile("canvas");
* builder.setAttribute("drawImage");
* builder.setServiceId(hostServiceId);
*
* DConnectResponseMessage response = sdk.post(builder.build(), dataMap);
* if (response.getResult() == DConnectMessage.RESULT_OK) {
* // 成功時の処理
* }
* </pre>
* </div>
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード2</span>
* <pre>
* DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
* DConnectSDK.URIBuilder builder = sdk.createURIBuilder();
* builder.setProfile("canvas");
* builder.setAttribute("drawImage");
* builder.setServiceId(hostServiceId);
*
* DConnectResponseMessage response = sdk.post(builder.build(), new StringEntity("テストデータ"));
* if (response.getResult() == DConnectMessage.RESULT_OK) {
* // 成功時の処理
* }
* </pre>
* </div>
* @param uri アクセス先のURI
* @param data 送信するボディデータ
* @return レスポンス
*/
public DConnectResponseMessage post(final Uri uri, final Entity data) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
return sendRequestInternal(Method.POST, uri, null, data);
}
/**
* 非同期にPOSTメソッドで指定したURIにアクセスし、レスポンスをリスナーに通知する.
*
* @param uri アクセス先のURI
* @param data 送信するボディデータ
* @param listener レスポンスを通知するリスナー
*/
public void post(final String uri, final Entity data, final OnResponseListener listener) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
post(Uri.parse(uri), data, listener);
}
/**
* 非同期にPOSTメソッドで指定したURIにアクセスし、レスポンスをリスナーに通知する.
*
* @param uri アクセス先のURI
* @param data 送信するボディデータ
* @param listener レスポンスを通知するリスナー
*/
public void post(final Uri uri, final Entity data, final OnResponseListener listener) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
mExecutorService.submit(new Runnable() {
@Override
public void run() {
DConnectResponseMessage result = post(uri, data);
if (listener != null) {
listener.onResponse(result);
}
}
});
}
/**
* DELETEメソッドで指定したURIにアクセスし、レスポンスを取得する.
* @param uri アクセス先のURI
* @return レスポンス
*/
public DConnectResponseMessage delete(final String uri) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
return delete(Uri.parse(uri));
}
/**
* DELETEメソッドで指定したURIにアクセスし、レスポンスを取得する.
* @param uri アクセス先のURI
* @return レスポンス
*/
public DConnectResponseMessage delete(final Uri uri) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
return sendRequestInternal(Method.DELETE, uri, null, null);
}
/**
* 非同期にDELETEメソッドで指定したURIにアクセスし、レスポンスをリスナーに通知する.
* @param uri アクセス先のURI
* @param listener レスポンスを通知するリスナー
*/
public void delete(final String uri, final OnResponseListener listener) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
delete(Uri.parse(uri), listener);
}
/**
* 非同期にDELETEメソッドで指定したURIにアクセスし、レスポンスをリスナーに通知する.
* @param uri アクセス先のURI
* @param listener レスポンスを通知するリスナー
*/
public void delete(final Uri uri, final OnResponseListener listener) {
if (uri == null) {
throw new NullPointerException("uri is null.");
}
mExecutorService.submit(new Runnable() {
@Override
public void run() {
DConnectResponseMessage result = delete(uri);
if (listener != null) {
listener.onResponse(result);
}
}
});
}
/**
* Availabilityプロファイルにアクセスし、レスポンスを取得する.
* <p>
* この関数のレスポンスからDevice Connect Managerの有効・無効を確認します。<br>
* この関数の中で、Device Connect Managerへの通信処理が発生しますので、UIスレッドから呼び出すことはできません。
* </p>
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
*
* DConnectResponseMessage response = sdk.availability();
* if (response.getResult() == DConnectMessage.RESULT_OK) {
* // Device Connect Managerが有効
* } else {
* // Device Connect Managerが無効
* }
* </pre>
* </div>
* @return レスポンス
*/
public DConnectResponseMessage availability() {
URIBuilder builder = new URIBuilder();
builder.setProfile(AvailabilityProfileConstants.PROFILE_NAME);
return get(builder.build());
}
/**
* 非同期にAvailabilityプロファイルにアクセスし、レスポンスをリスナーに通知する.
* <p>
* この関数のレスポンスからDevice Connect Managerの有効・無効を確認します。<br>
* </p>
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
*
* DConnectResponseMessage response = sdk.availability(new OnResponseListener() {
* <code>@</code>Override
* public void onResponse(DConnectResponseMessage response) {
* if (response.getResult() == DConnectMessage.RESULT_OK) {
* // Device Connect Managerが有効
* } else {
* // Device Connect Managerが無効
* }
* }
* });
* </pre>
* </div>
* @param listener 結果を通知するリスナー
*/
public void availability(final OnResponseListener listener) {
mExecutorService.submit(new Runnable() {
@Override
public void run() {
DConnectResponseMessage result = availability();
if (listener != null) {
listener.onResponse(result);
}
}
});
}
/**
* 同期的にLocal OAuth処理を行う。
* <p>
* ユーザに使用許可ダイアログを表示して確認を行います。<br>
* この関数の中で、Device Connect Managerへの通信処理が発生しますので、UIスレッドから呼び出すことはできません。
* </p>
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
*
* String[] scopes = {
* "serviceDiscovery",
* "serviceInformation",
* "battery"
* };
*
* DConnectResponseMessage response = sdk.authorization("SampleApp", scopes);
* if (response.getResult() == DConnectMessage.RESULT_OK) {
* // Local OAuthの認証に成功
* String accessToken = response.getString("accessToken");
* sdk.setAccessToken(accessToken);
* } else {
* // Local OAuthの認証に失敗
* }
* </pre>
* </div>
* @param appName アプリケーション名
* @param scopes アクセスするプロファイル一覧
* @return レスポンス
*/
public DConnectResponseMessage authorization(final String appName, final String[] scopes) {
DConnectResponseMessage response = createCreateClient();
if (response.getResult() == DConnectMessage.RESULT_ERROR) {
return response;
}
String clientId = response.getString(DConnectMessage.EXTRA_CLIENT_ID);
return createAccessToken(clientId, appName, scopes);
}
/**
* 非同期にLocal OAuth処理を行い、リスナーに結果を通知する.
* <p>
* ユーザに使用許可ダイアログを表示して確認を行います。<br>
* </p>
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* final DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
*
* String[] scopes = {
* "serviceDiscovery",
* "serviceInformation",
* "battery"
* };
*
* DConnectResponseMessage response = sdk.authorization("SampleApp", scopes, new OnAuthorizationListener() {
* <code>@</code>Override
* public void onResponse(String clientId, String accessToken) {
* // Local OAuthの認証に成功
* sdk.setAccessToken(accessToken);
* }
* <code>@</code>Override
* public void onError(int errorCode, String errorMessage) {
* // Local OAuthの認証に失敗
* }
* });
* </pre>
* </div>
* @param appName アプリケーション名
* @param scopes アクセスするプロファイル一覧
* @param listener Local OAuthのレスポンスを通知するリスナー
*/
public void authorization(final String appName, final String[] scopes, final OnAuthorizationListener listener) {
mExecutorService.submit(new Runnable() {
@Override
public void run() {
DConnectResponseMessage response = createCreateClient();
if (response.getResult() == DConnectMessage.RESULT_ERROR) {
if (listener != null) {
listener.onError(response.getErrorCode(), response.getErrorMessage());
}
return;
}
String clientId = response.getString(DConnectMessage.EXTRA_CLIENT_ID);
response = createAccessToken(clientId, appName, scopes);
if (response.getResult() == DConnectMessage.RESULT_ERROR) {
if (listener != null) {
listener.onError(response.getErrorCode(), response.getErrorMessage());
}
} else {
String accessToken = response.getString(AuthorizationProfileConstants.PARAM_ACCESS_TOKEN);
listener.onResponse(clientId, accessToken);
}
}
});
}
/**
* ServiceDiscoveryプロファイルにアクセスし、Device Connect Managerに接続されているサービス一覧を取得する.
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
* sdk.setAccessToken("xxxxxxx");
*
* DConnectResponseMessage response = sdk.serviceDiscovery();
* if (response.getResult() == DConnectMessage.RESULT_OK) {
* // サービス一覧の取得に成功
* List<Object> services = response.getList(ServiceDiscoveryProfileConstants.PARAM_SERVICES);
* for (Object obj : services) {
* DConnectMessage service = (DConnectMessage) obj;
* String serviceId = service.getString(ServiceDiscoveryProfileConstants.PARAM_ID);
* String name = service.getString(ServiceDiscoveryProfileConstants.PARAM_NAME);
* boolean online = service.getBoolean(ServiceDiscoveryProfileConstants.PARAM_ONLINE);
* }
* } else {
* // サービス一覧の取得に失敗
* }
* </pre>
* </div>
* @return レスポンス
*/
public DConnectResponseMessage serviceDiscovery() {
URIBuilder builder = new URIBuilder();
builder.setProfile(ServiceDiscoveryProfileConstants.PROFILE_NAME);
return get(builder.build());
}
/**
* 非同期にServiceDiscoveryプロファイルにアクセスし、Device Connect Managerに接続されているサービス一覧をリスナーに通知する.
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* DConnectSDK sdk = DConnectSDKFactory.create(context, DConnectSDKFactory.Type.HTTP);
* sdk.setAccessToken("xxxxxxx");
*
* DConnectResponseMessage response = sdk.serviceDiscovery(new OnResponseListener() {
* <code>@</code>Override
* public void onResponse(DConnectResponseMessage response) {
* if (response.getResult() == DConnectMessage.RESULT_OK) {
* // サービス一覧の取得に成功
* } else {
* // サービス一覧の取得に失敗
* }
* }
* });
* </pre>
* </div>
* @param listener レスポンスを通知するリスナー
*/
public void serviceDiscovery(final OnResponseListener listener) {
mExecutorService.submit(new Runnable() {
@Override
public void run() {
DConnectResponseMessage result = serviceDiscovery();
if (listener != null) {
listener.onResponse(result);
}
}
});
}
/**
* ServiceInformationプロファイルにアクセスし、サービスの情報を取得する.
* @param serviceId サービスID
* @return レスポンス
*/
public DConnectResponseMessage getServiceInformation(final String serviceId) {
if (serviceId == null) {
throw new NullPointerException("serviceId is null.");
}
URIBuilder builder = new URIBuilder();
builder.setProfile(ServiceInformationProfileConstants.PROFILE_NAME);
builder.setServiceId(serviceId);
return get(builder.build());
}
/**
* 非同期にServiceInformationプロファイルにアクセスし、サービスの情報を取得する.
* @param serviceId サービスID
* @param listener レスポンスを通知するリスナー
*/
public void getServiceInformation(final String serviceId, final OnResponseListener listener) {
if (serviceId == null) {
throw new NullPointerException("serviceId is null.");
}
mExecutorService.submit(new Runnable() {
@Override
public void run() {
DConnectResponseMessage result = getServiceInformation(serviceId);
if (listener != null) {
listener.onResponse(result);
}
}
});
}
private DConnectResponseMessage createCreateClient() {
URIBuilder builder = new URIBuilder();
builder.setProfile(AuthorizationProfileConstants.PROFILE_NAME);
builder.setAttribute(AuthorizationProfileConstants.ATTRIBUTE_GRANT);
return get(builder.build());
}
private DConnectResponseMessage createAccessToken(final String clientId, final String appName, final String[] scopes) {
URIBuilder builder = new URIBuilder();
builder.setProfile(AuthorizationProfileConstants.PROFILE_NAME);
builder.setAttribute(AuthorizationProfileConstants.ATTRIBUTE_ACCESS_TOKEN);
builder.addParameter(AuthorizationProfileConstants.PARAM_CLIENT_ID, clientId);
builder.addParameter(AuthorizationProfileConstants.PARAM_APPLICATION_NAME, appName);
builder.addParameter(AuthorizationProfileConstants.PARAM_SCOPE, combineStr(scopes));
return get(builder.build());
}
private String combineStr(final String[] scopes) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < scopes.length; i++) {
if (i > 0) {
builder.append(",");
}
builder.append(scopes[i].trim());
}
return builder.toString();
}
DConnectResponseMessage createErrorMessage(final int errorCode, final String errorMessage) {
DConnectResponseMessage message = new DConnectResponseMessage(DConnectMessage.RESULT_ERROR);
message.setErrorCode(errorCode);
message.setErrorMessage(errorMessage);
return message;
}
DConnectResponseMessage createTimeoutResponse() {
return new DConnectResponseMessage(DConnectMessage.ErrorCode.TIMEOUT);
}
/**
* 指定された情報からAPIへのURLを提供するクラス.
* <p>
* Host、Port、AccessTokenは、DConnectSDKに設定された値がデフォルトで入っています。
* </p>
* <div>
* <span style="margin:0;padding:2px;background:#029EBC;color:#EBF7FA;line-height:140%;font-weight:bold;">サンプルコード</span>
* <pre>
* URIBuilder builder = sdk.createURIBuilder();
* builder.setProfile(BatteryProfileConstants.PROFILE_NAME)
* .setAttribute(BatteryProfileConstants.ATTRIBUTE_ON_BATTERY_CHANGE)
* .addParameter(DConnectMessage.EXTRA_SERVICE_ID, "xxxxxxxx")
*
* URI uri = builder.build();
* String uriStr = builder.toString(true);
* </pre>
* </div>
* @author NTT DOCOMO, INC.
*/
public class URIBuilder {
/**
* スキーム.
*/
private String mScheme = isSSL() ? "https" : "http";
/**
* ホスト.
*/
private String mHost = DConnectSDK.this.mHost;
/**
* ポート番号.
*/
private int mPort = DConnectSDK.this.mPort;
/**
* パス.
*/
private String mPath;
/**
* パラメータ.
*/
private Map<String, String> mParameters = new HashMap<>();
/**
* API.
*/
private String mApi = DConnectMessage.DEFAULT_API;
/**
* プロファイル.
*/
private String mProfile;
/**
* インターフェース.
*/
private String mInterface;
/**
* アトリビュート.
*/
private String mAttribute;
/**
* コンストラクタ.
*/
URIBuilder() {
if (mAccessToken != null) {
addParameter(DConnectMessage.EXTRA_ACCESS_TOKEN, mAccessToken);
}
}
/**
* URIから {@link URIBuilder} クラスを生成する.
*
* @param uri URI
* @throws URISyntaxException URIフォーマットが不正な場合
*/
URIBuilder(final String uri) throws URISyntaxException {
this(new URI(uri));
}
/**
* URIから {@link URIBuilder} クラスを生成する.
*
* @param uri URI
*/
URIBuilder(final URI uri) {
mScheme = uri.getScheme();
mHost = uri.getHost();
mPort = uri.getPort();
mPath = uri.getPath();
String query = uri.getQuery();
if (query != null) {
String[] params = query.split("&");
for (String param : params) {
String[] splitted = param.split("=");
if (splitted.length == 2) {
addParameter(splitted[0], splitted[1]);
} else {
addParameter(splitted[0], "");
}
}
}
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return toString(false);
}
/**
* ASCIIのオブジェクト文字列を取得する.
*
* @return オブジェクト文字列
*/
public String toASCIIString() {
return toString(true);
}
/**
* スキームを取得する.
*
* @return スキーム
*/
public String getScheme() {
return mScheme;
}
/**
* スキームを設定する.
*
* @param scheme スキーム
* @return {@link URIBuilder} インスタンス
*/
public URIBuilder setScheme(final String scheme) {
if (scheme == null) {
throw new NullPointerException("scheme is null.");
}
if (scheme.isEmpty()) {
throw new IllegalArgumentException("scheme is empty.");
}
mScheme = scheme;
return this;
}
/**
* ホスト名を取得する.
*
* @return ホスト名
*/
public String getHost() {
return mHost;
}
/**
* ホスト名を設定する.
* <p>
* {@link DConnectSDK#setHost(String)}で設定された値がでデフォルトでは設定されています。
* </p>
* @param host ホスト名
* @return {@link URIBuilder} インスタンス
*/
public URIBuilder setHost(final String host) {
if (host == null) {
throw new NullPointerException("host is null.");
}
if (host.isEmpty()) {
throw new IllegalArgumentException("host is empty.");
}
mHost = host;
return this;
}
/**
* ポート番号を取得する. ポート番号が指定されていない場合は-1を返す
*
* @return ポート番号
*/
public int getPort() {
return mPort;
}
/**
* ポート番号を設定する.
* <p>
* {@link DConnectSDK#setPort(int)}で設定された値がでデフォルトでは設定されています。
* </p>
* @param port ポート番号
* @return {@link URIBuilder} インスタンス
*/
public URIBuilder setPort(final int port) {
if (port < 0 || port > 65535) {
throw new IllegalArgumentException("port is invalid. port=" + port);
}
mPort = port;
return this;
}
/**
* パスを取得する.
*
* @return パス
*/
public String getPath() {
return mPath;
}
/**
* APIのパスを文字列で設定する.
* <p>
* このパラメータが設定されている場合はビルド時に api、profile、interface、attribute は無視される。
* </p>
* @param path パス
* @return {@link URIBuilder} インスタンス
*/
public URIBuilder setPath(final String path) {
mPath = path;
return this;
}
/**
* APIを取得する.
*
* @return API
*/
public String getApi() {
return mApi;
}
/**
* APIを取得する.
* <p>
* パスが設定されている場合には、このパラメータは無視される。<br>
* デフォルトでは、gotapiが設定されています。
* </p>
* @param api API
* @return {@link URIBuilder} インスタンス
*/
public URIBuilder setApi(final String api) {
mApi = api;
return this;
}
/**
* プロファイルを取得する.
*
* @return プロファイル
*/
public String getProfile() {
return mProfile;
}
/**
* プロファイルを設定する.
* <p>
* {@link #setPath}でパスが設定されている場合には、このパラメータは無視される。<br>
* </p>
* @param profile プロファイル
* @return {@link URIBuilder} インスタンス
*/
public URIBuilder setProfile(final String profile) {
mProfile = profile;
return this;
}
/**
* インターフェースを取得する.
*
* @return インターフェース
*/
public String getInterface() {
return mInterface;
}
/**
* インターフェースを設定する.
* <p>
* {@link #setPath}でパスが設定されている場合には、このパラメータは無視される。<br>
* {@code null}が設定された場合には、インターフェースは省略されます。
* </p>
* @param inter インターフェース
* @return {@link URIBuilder} インスタンス
*/
public URIBuilder setInterface(final String inter) {
mInterface = inter;
return this;
}
/**
* アトリビュートを取得する.
*
* @return アトリビュート
*/
public String getAttribute() {
return mAttribute;
}
/**
* アトリビュートを設定する.
* <p>
* {@link #setPath}でパスが設定されている場合には、このパラメータは無視される。<br>
* {@code null}が設定された場合には、アトリビュートは省略されます。
* </p>
* @param attribute アトリビュート
* @return {@link URIBuilder} インスタンス
*/
public URIBuilder setAttribute(final String attribute) {
mAttribute = attribute;
return this;
}
/**
* アクセストークンを設定する.
* <p>
* {@link HttpDConnectSDK#setAccessToken}で設定された値がデフォルトで指定されている。<br>
* ここで、新たなアクセストークンが指定された場合には上書きする。
* </p>
* @param accessToken アクセストークン
* @return {@link URIBuilder} インスタンス
*/
public URIBuilder setAccessToken(final String accessToken) {
addParameter(DConnectMessage.EXTRA_ACCESS_TOKEN, accessToken);
return this;
}
/**
* アクセストークンを取得する.
* @return アクセストークン
*/
public String getAccessToken() {
return getParameter(DConnectMessage.EXTRA_ACCESS_TOKEN);
}
/**
* サービスIDを設定する.
* @param serviceId サービスID
* @return {@link URIBuilder} インスタンス
*/
public URIBuilder setServiceId(final String serviceId) {
addParameter(DConnectMessage.EXTRA_SERVICE_ID, serviceId);
return this;
}
/**
* サービスIDを取得する.
* <p>
* 設定されていない場合にはnullを返却する。
* </p>
* @return サービスID
*/
public String getServiceId() {
return getParameter(DConnectMessage.EXTRA_SERVICE_ID);
}
/**
* 指定したクエリパラメータを取得する.
* <p>
* 指定されたクエリパラメータが存在しない場合にはnullを返却する。
* </p>
* @param name クエリパラメータ名
* @return クエリパラメータ
*/
public String getParameter(final String name) {
return mParameters.get(name);
}
/**
* キーバリューでクエリパラメータを追加する.
*
* @param key キー
* @param value バリュー
* @return {@link URIBuilder} インスタンス
*/
public URIBuilder addParameter(final String key, final String value) {
if (key == null) {
throw new NullPointerException("key is null.");
}
if (value == null) {
throw new NullPointerException("value is null.");
}
mParameters.put(key, value);
return this;
}
/**
* 指定されたクエリパラメータを削除する.
* @param key クエリパラメータ名
* @return {@link URIBuilder} インスタンス
*/
public URIBuilder removeParameter(final String key) {
if (key == null) {
throw new NullPointerException("key is null.");
}
mParameters.remove(key);
return this;
}
/**
* {@link Uri} オブジェクトを取得する.
*
* @return {@link Uri} オブジェクト
*/
public Uri build() {
return Uri.parse(toString(true));
}
/**
* URIを文字列にして取得する.
*
* @param ascii ASCII変換の有無
* @return URIを表す文字列
*/
private String toString(final boolean ascii) {
StringBuilder builder = new StringBuilder();
if (mScheme != null) {
builder.append(mScheme);
builder.append("://");
}
if (mHost != null) {
builder.append(mHost);
}
if (mPort > 0) {
builder.append(":");
builder.append(mPort);
}
if (mPath != null) {
builder.append(mPath);
} else {
if (mApi != null) {
builder.append("/");
builder.append(mApi);
}
if (mProfile != null) {
builder.append("/");
builder.append(mProfile);
}
if (mInterface != null) {
builder.append("/");
builder.append(mInterface);
}
if (mAttribute != null) {
builder.append("/");
builder.append(mAttribute);
}
}
if (mParameters != null && mParameters.size() > 0) {
if (ascii) {
builder.append("?");
builder.append(concatenateStringWithEncode(mParameters, "UTF-8"));
} else {
builder.append("?");
builder.append(concatenateString(mParameters));
}
}
return builder.toString();
}
private String concatenateString(final Map<String, String> map) {
String string = "";
for (Map.Entry<String, String> e : map.entrySet()) {
if (string.length() > 0) {
string += "&";
}
string += e.getKey() + "=" + e.getValue();
}
return string;
}
private String concatenateStringWithEncode(final Map<String, String> map, final String charset) {
try {
String string = "";
for (Map.Entry<String, String> e : map.entrySet()) {
if (string.length() > 0) {
string += "&";
}
string += e.getKey() + "=" + URLEncoder.encode(e.getValue(), charset);
}
return string;
} catch (UnsupportedEncodingException e) {
return "";
}
}
}
/**
* 非同期でDevice Connect Managerからのレスポンスを受け取るためのリスナー.
* @author NTT DOCOMO, INC.
*/
public interface OnResponseListener {
/**
* レスポンスを受け取った時に通知される.
* @param response レスポンス
*/
void onResponse(DConnectResponseMessage response);
}
/**
* Device Connect Managerからイベントを受け取るためのリスナー.
* @author NTT DOCOMO, INC.
*/
public interface OnEventListener extends OnResponseListener {
/**
* イベントを通知する.
* @param message イベントメッセージ
*/
void onMessage(DConnectEventMessage message);
}
/**
* 非同期でDevice Connect Managerの認証結果を受け取るリスナー.
* @author NTT DOCOMO, INC.
*/
public interface OnAuthorizationListener {
/**
* 認証に成功した結果を通知する.
* <p>
* このリスナーで受け取ったアクセストークンを使うことで、Device Connect Manager
* の各プロファイルにアクセスすることができるようになります。
* </p>
* @param clientId クライアントID
* @param accessToken アクセストークン
*/
void onResponse(String clientId, String accessToken);
/**
* 認証に失敗した結果を通知する.
* @param errorCode エラーコード
* @param errorMessage エラーメッセージ
*/
void onError(int errorCode, String errorMessage);
}
/**
* WebSocketとの接続状態を通知するリスナー.
* @author NTT DOCOMO, INC.
*/
public interface OnWebSocketListener {
/**
* 接続確立を通知する.
*/
void onOpen();
/**
* 接続切断を通知する.
*/
void onClose();
/**
* 接続のエラーが発生したことを通知する.
* @param e 発生した時の例外
*/
void onError(Exception e);
}
}