/* DConnectProfileSpec.java Copyright (c) 2016 NTT DOCOMO,INC. Released under the MIT license http://opensource.org/licenses/mit-license.php */ package org.deviceconnect.android.profile.spec; import android.os.Bundle; import org.deviceconnect.message.DConnectMessage; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * プロファイルについての仕様を保持するクラス. * <p> * 当該プロファイル上で定義されるAPIの仕様のリストを持つ. * </p> * @author NTT DOCOMO, INC. */ public class DConnectProfileSpec implements DConnectSpecConstants { private Bundle mBundle; String mApiName; String mProfileName; private Map<String, Map<Method, DConnectApiSpec>> mAllApiSpecs; private DConnectProfileSpec() { } /** * API仕様定義ファイルから生成したBundleのインスタンスを設定する. * @param bundle Bundleのインスタンス */ void setBundle(final Bundle bundle) { mBundle = new Bundle(); deepCopy(bundle, mBundle); } /** * API仕様定義ファイルから取得したAPI名を設定する. * @param apiName API名 */ void setApiName(final String apiName) { mApiName = apiName; } /** * API名を取得する. * @return API名 */ public String getApiName() { return mApiName; } /** * API仕様定義ファイルから取得したプロファイル名を設定する. * @param profileName プロファイル名 */ void setProfileName(final String profileName) { mProfileName = profileName; } /** * プロファイル名を取得する. * @return プロファイル名 */ public String getProfileName() { return mProfileName; } /** * APIの仕様定義のマップを設定する. * @param apiSpecs {@link DConnectApiSpec}のマップ */ void setApiSpecs(final Map<String, Map<Method, DConnectApiSpec>> apiSpecs) { mAllApiSpecs = apiSpecs; } /** * 当該プロファイル上で定義されている、APIの仕様定義のリストを取得する. * @return {@link DConnectApiSpec}のリスト */ public List<DConnectApiSpec> getApiSpecList() { List<DConnectApiSpec> list = new ArrayList<DConnectApiSpec>(); if (mAllApiSpecs == null) { return list; } for (Map<Method, DConnectApiSpec> apiSpecs : mAllApiSpecs.values()) { for (DConnectApiSpec apiSpec : apiSpecs.values()) { list.add(apiSpec); } } return list; } /** * 指定されたパスで提供されるAPIの仕様定義のマップを取得する. * @param path APIのパス * @return {@link DConnectApiSpec}のマップ. キーはメソッド名. * 指定されたパスで提供しているAPIが存在しない場合は<code>null</code> */ public Map<Method, DConnectApiSpec> findApiSpecs(final String path) { if (path == null) { throw new IllegalArgumentException("path is null."); } return mAllApiSpecs.get(path.toLowerCase()); } /** * 指定されたパスとメソッドで提供されるAPIの仕様定義を取得する. * @param path APIのパス * @param method APIのメソッド名 * @return {@link DConnectApiSpec}のインスタンス. * 指定されたパスとメソッドで提供しているAPIが存在しない場合は<code>null</code> */ public DConnectApiSpec findApiSpec(final String path, final Method method) { if (method == null) { throw new IllegalArgumentException("method is null."); } Map<Method, DConnectApiSpec> apiSpecsOfPath = findApiSpecs(path); if (apiSpecsOfPath == null) { return null; } return apiSpecsOfPath.get(method); } /** * API仕様定義ファイルから生成したBundleのインスタンスを取得する. * @return Bundleのインスタンス */ public Bundle toBundle() { Bundle dst = new Bundle(); deepCopy(mBundle, dst); return dst; } static void deepCopy(final Bundle src, final Bundle dst) { for (String key : src.keySet()) { Object obj = src.get(key); if (obj == null) { continue; } // NOTE: // 本メソッドに入力される Bundle オブジェクトは JSONObject を変換して得たもの. // つまり、その Bundle オブジェクトは下記の型のみを含む. // int, long, double, boolean, String, // int[], long[], double[], boolean[], String[], // Bundle // よって、ここでは上記の型の値のみをコピーする. if (obj instanceof Bundle) { Bundle a = (Bundle) obj; Bundle b = new Bundle(); deepCopy(a, b); dst.putBundle(key, b); } else if (obj instanceof int[]) { int[] a = (int[]) obj; int[] b = new int[a.length]; System.arraycopy(a, 0, b, 0, a.length); dst.putIntArray(key, b); } else if (obj instanceof long[]) { long[] a = (long[]) obj; long[] b = new long[a.length]; System.arraycopy(a, 0, b, 0, a.length); dst.putLongArray(key, b); } else if (obj instanceof double[]) { double[] a = (double[]) obj; double[] b = new double[a.length]; System.arraycopy(a, 0, b, 0, a.length); dst.putDoubleArray(key, b); } else if (obj instanceof boolean[]) { boolean[] a = (boolean[]) obj; boolean[] b = new boolean[a.length]; System.arraycopy(a, 0, b, 0, a.length); dst.putBooleanArray(key, b); } else if (obj instanceof String[]) { String[] a = (String[]) obj; String[] b = new String[a.length]; System.arraycopy(a, 0, b, 0, a.length); dst.putStringArray(key, b); } else if (obj instanceof Serializable) { // int, long, double, boolean, String のいずれか. dst.putSerializable(key, (Serializable) obj); } } } /** * {@link DConnectProfileSpec}のビルダー. * * @author NTT DOCOMO, INC. */ public static class Builder { private final Map<String, Map<Method, DConnectApiSpec>> mAllApiSpecs = new HashMap<String, Map<Method, DConnectApiSpec>>(); private Bundle mBundle; private String mApiName; private String mProfileName; /** * APIの仕様定義を追加する. * * @param path パス * @param method メソッド * @param apiSpec 仕様定義 * @return ビルダー自身のインスタンス */ public Builder addApiSpec(final String path, final Method method, final DConnectApiSpec apiSpec) { String[] names = path.split("/"); if (names.length == 2) { if (!names[1].equals("")) { apiSpec.setAttributeName(names[1]); } } else if (names.length == 3) { apiSpec.setInterfaceName(names[1]); apiSpec.setAttributeName(names[2]); } String pathKey = path.toLowerCase(); Map<Method, DConnectApiSpec> apiSpecs = mAllApiSpecs.get(pathKey); if (apiSpecs == null) { apiSpecs = new HashMap<Method, DConnectApiSpec>(); mAllApiSpecs.put(pathKey, apiSpecs); } apiSpecs.put(method, apiSpec); return this; } /** * API仕様定義ファイルから生成したBundleのインスタンスを取得する. * * @param bundle Bundleのインスタンス * @return ビルダー自身のインスタンス */ public Builder setBundle(final Bundle bundle) { mBundle = bundle; return this; } /** * API仕様定義ファイルから取得したAPI名を設定する. * @param apiName API名 */ public Builder setApiName(final String apiName) { mApiName = apiName; return this; } /** * API仕様定義ファイルから取得したプロファイル名を設定する. * @param profileName プロファイル名 */ public Builder setProfileName(final String profileName) { mProfileName = profileName; return this; } /** * {@link DConnectProfileSpec}のインスタンスを生成する. * * @return {@link DConnectProfileSpec}のインスタンス */ public DConnectProfileSpec build() { DConnectProfileSpec profileSpec = new DConnectProfileSpec(); profileSpec.setApiName(mApiName != null ? mApiName : DConnectMessage.DEFAULT_API); profileSpec.setProfileName(mProfileName); profileSpec.setApiSpecs(mAllApiSpecs); profileSpec.setBundle(mBundle); return profileSpec; } } }