org.deviceconnect.android.profile.restful.test.RESTfulDConnectTestCase.java Source code

Java tutorial

Introduction

Here is the source code for org.deviceconnect.android.profile.restful.test.RESTfulDConnectTestCase.java

Source

/*
 RESTfulDConnectTestCase.java
 Copyright (c) 2014 NTT DOCOMO,INC.
 Released under the MIT license
 http://opensource.org/licenses/mit-license.php
 */
package org.deviceconnect.android.profile.restful.test;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import junit.framework.Assert;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.mime.content.AbstractContentBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.deviceconnect.android.test.DConnectTestCase;
import org.deviceconnect.message.DConnectMessage;
import org.deviceconnect.profile.AuthorizationProfileConstants;
import org.deviceconnect.profile.NetworkServiceDiscoveryProfileConstants;
import org.deviceconnect.profile.SystemProfileConstants;
import org.deviceconnect.utils.URIBuilder;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

/**
 * RESTful API.
 * @author NTT DOCOMO, INC.
 */
public class RESTfulDConnectTestCase extends DConnectTestCase {

    /** ??. */
    private static final int WAIT_FOR_EVENT = 10000;
    /** ?. */
    private static final int BUF_SIZE = 8192;
    /** . */
    private static final int RETRY_COUNT = 3;

    /** . */
    private final Object mLockObj = new Object();

    /**
     * .
     * @param tag 
     */
    public RESTfulDConnectTestCase(final String tag) {
        super(tag);
    }

    /**
     * ?API????.
     * 
     * @param scopes 
     * @return ?????
     */
    private static String createScopeParameter(final String[] scopes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < scopes.length; i++) {
            if (i > 0) {
                sb.append(",");
            }
            sb.append(scopes[i]);
        }
        return sb.toString();
    }

    @Override
    protected String[] createClient(final String packageName) {
        URIBuilder builder = TestURIBuilder.createURIBuilder();
        builder.setProfile(AuthorizationProfileConstants.PROFILE_NAME);
        builder.setAttribute(AuthorizationProfileConstants.ATTRIBUTE_CREATE_CLIENT);
        builder.addParameter(AuthorizationProfileConstants.PARAM_PACKAGE, packageName);
        try {
            HttpGet request = new HttpGet(builder.toString());
            JSONObject root = sendRequest(request, false);
            assertResultOK(root);
            String clientId = root.getString(AuthorizationProfileConstants.PARAM_CLIENT_ID);
            String clientSecret = root.getString(AuthorizationProfileConstants.PARAM_CLIENT_SECRET);
            if (clientId != null && clientSecret != null) {
                return new String[] { clientId, clientSecret };
            }
        } catch (JSONException e) {
            fail();
        }
        return null;
    }

    @Override
    protected String requestAccessToken(final String clientId, final String clientSecret, final String[] scopes) {
        URIBuilder builder = TestURIBuilder.createURIBuilder();
        builder.setProfile(AuthorizationProfileConstants.PROFILE_NAME);
        builder.setAttribute(AuthorizationProfileConstants.ATTRIBUTE_REQUEST_ACCESS_TOKEN);
        builder.addParameter(AuthorizationProfileConstants.PARAM_CLIENT_ID, clientId);
        builder.addParameter(AuthorizationProfileConstants.PARAM_GRANT_TYPE, "authorization_code");
        builder.addParameter(AuthorizationProfileConstants.PARAM_SCOPE, createScopeParameter(scopes));
        builder.addParameter(AuthorizationProfileConstants.PARAM_APPLICATION_NAME, "dConnectManagerTest");
        builder.addParameter(AuthorizationProfileConstants.PARAM_SIGNATURE,
                createSignature(clientId, scopes, clientSecret));
        try {
            HttpGet request = new HttpGet(builder.toString());
            JSONObject root = sendRequestInternal(request, false);
            assertResultOK(root);
            return root.getString(AuthorizationProfileConstants.PARAM_ACCESS_TOKEN);
        } catch (JSONException e) {
            fail("Exception in JSONObject." + e.getMessage());
        }
        return null;
    }

    /**
     * ?RestfulAPI???.
     * @return ?
     */
    @Override
    protected List<DeviceInfo> searchDevices() {
        List<DeviceInfo> services = new ArrayList<DeviceInfo>();
        HttpGet request = new HttpGet(DCONNECT_MANAGER_URI + "/network_service_discovery/getnetworkservices");
        try {
            JSONObject root = sendRequest(request);
            assertResultOK(root);

            JSONArray servicesJson = root.getJSONArray(NetworkServiceDiscoveryProfileConstants.PARAM_SERVICES);
            for (int i = 0; i < servicesJson.length(); i++) {
                JSONObject serviceJson = servicesJson.getJSONObject(i);
                String deviceId = serviceJson.getString(NetworkServiceDiscoveryProfileConstants.PARAM_ID);
                String deviceName = serviceJson.getString(NetworkServiceDiscoveryProfileConstants.PARAM_NAME);
                services.add(new DeviceInfo(deviceId, deviceName));
            }
        } catch (JSONException e) {
            fail("Exception in JSONObject." + e.getMessage());
        }
        return services;
    }

    @Override
    protected List<PluginInfo> searchPlugins() {
        List<PluginInfo> plugins = new ArrayList<PluginInfo>();
        URIBuilder builder = TestURIBuilder.createURIBuilder();
        builder.setProfile(SystemProfileConstants.PROFILE_NAME);
        try {
            HttpUriRequest request = new HttpGet(builder.toString());
            JSONObject response = sendRequest(request);
            assertResultOK(response);

            JSONArray pluginsJson = response.getJSONArray(SystemProfileConstants.PARAM_PLUGINS);
            for (int i = 0; i < pluginsJson.length(); i++) {
                JSONObject pluginJson = pluginsJson.getJSONObject(i);
                String id = pluginJson.getString(SystemProfileConstants.PARAM_ID);
                String name = pluginJson.getString(SystemProfileConstants.PARAM_NAME);
                plugins.add(new PluginInfo(id, name));
            }
        } catch (JSONException e) {
            fail("Exception in JSONObject." + e.getMessage());
        }
        return plugins;
    }

    /**
     * HTTP???.
     * @param uri ??URI
     * @return 
     */
    protected final byte[] getBytesFromHttp(final String uri) {
        HttpUriRequest request = new HttpGet(uri);
        HttpClient client = new DefaultHttpClient();
        try {
            HttpResponse response = client.execute(request);
            switch (response.getStatusLine().getStatusCode()) {
            case HttpStatus.SC_OK:
                InputStream in = response.getEntity().getContent();
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] buf = new byte[BUF_SIZE];
                int len;
                while ((len = in.read(buf)) > 0) {
                    baos.write(buf, 0, len);
                }
                return baos.toByteArray();
            case HttpStatus.SC_NOT_FOUND:
                Assert.fail("Not found page. 404: " + uri);
                break;
            default:
                Assert.fail("Connection Error. " + response.getStatusLine().getStatusCode());
                break;
            }
        } catch (ClientProtocolException e) {
            Assert.fail("ClientProtocolException: " + e.getMessage());
        } catch (IOException e) {
            Assert.fail("IOException: " + e.getMessage());
        }
        return null;
    }

    /**
     * RESTful?dConnectManager??.
     * @param request Http
     * @return HttpResponse
     */
    protected final HttpResponse requestHttpResponse(final HttpUriRequest request) {
        HttpClient client = new DefaultHttpClient();
        try {
            return client.execute(request);
        } catch (ClientProtocolException e) {
            Assert.fail("ClientProtocolException: " + e.getMessage());
        } catch (IOException e) {
            Assert.fail("IOException: " + e.getMessage());
        }
        return null;
    }

    /**
     * RESTful?dConnectManager??.
     * @param request Http
     * @return ??intent
     */
    protected final JSONObject sendRequest(final HttpUriRequest request) {
        return sendRequest(request, true);
    }

    /**
     * HTTP??.
     * @param request HTTP
     * @param requiredAuth ????????????
     * @return ?
     */
    protected final JSONObject sendRequest(final HttpUriRequest request, final boolean requiredAuth) {
        return sendRequest(request, requiredAuth, 0);
    }

    /**
     * HTTP??.
     * @param request HTTP
     * @param requiredAuth ????????????
     * @param count ?
     * @return ?
     */
    protected final JSONObject sendRequest(final HttpUriRequest request, final boolean requiredAuth,
            final int count) {
        try {
            JSONObject response = sendRequestInternal(request, requiredAuth);
            int result = response.getInt(DConnectMessage.EXTRA_RESULT);
            if (result == DConnectMessage.RESULT_ERROR && count <= RETRY_COUNT) {
                if (!response.has(DConnectMessage.EXTRA_ERROR_CODE)) {
                    return response;
                }
                int errorCode = response.getInt(DConnectMessage.EXTRA_ERROR_CODE);
                if (errorCode == DConnectMessage.ErrorCode.EXPIRED_ACCESS_TOKEN.getCode()) {
                    mAccessToken = requestAccessToken(mClientId, mClientSecret, PROFILES);
                    assertNotNull(mAccessToken);
                    storeOAuthInfo(mClientId, mClientSecret, mAccessToken);

                    URI uri = request.getURI();
                    URIBuilder builder = new URIBuilder(uri);
                    builder.addParameter(AuthorizationProfileConstants.PARAM_ACCESS_TOKEN, getAccessToken());

                    final HttpUriRequest newRequest;
                    if (request instanceof HttpGet) {
                        newRequest = new HttpGet(builder.toString());
                    } else if (request instanceof HttpPost) {
                        HttpPost newPostRequest = new HttpPost(builder.toString());
                        newPostRequest.setEntity(((HttpPost) request).getEntity());
                        newRequest = newPostRequest;
                    } else if (request instanceof HttpPut) {
                        HttpPut newPostRequest = new HttpPut(builder.toString());
                        newPostRequest.setEntity(((HttpPost) request).getEntity());
                        newRequest = newPostRequest;
                    } else if (request instanceof HttpDelete) {
                        newRequest = new HttpDelete(builder.toString());
                    } else {
                        fail("Invalid method is specified: " + request.getMethod());
                        return null;
                    }
                    return sendRequest(newRequest, requiredAuth, count + 1);
                }
            }
            return response;
        } catch (JSONException e) {
            Assert.fail("IOException: " + e.getMessage());
        }
        return null;
    }

    /**
     * RESTful?dConnectManager??.
     * @param request Http
     * @param requiredAuth OAuth???????????????.true?????
     * @return ??intent
     */
    protected final JSONObject sendRequestInternal(final HttpUriRequest request, final boolean requiredAuth) {
        try {
            HttpResponse response = requestHttpResponse(request);
            if (response == null) {
                return null;
            }
            switch (response.getStatusLine().getStatusCode()) {
            case HttpStatus.SC_OK:
                String msg = EntityUtils.toString(response.getEntity(), "UTF-8");
                try {
                    return new JSONObject(msg);
                } catch (JSONException e) {
                    Assert.fail("JSON Format error: " + msg);
                }
                break;
            case HttpStatus.SC_NOT_FOUND:
                Assert.fail("Not found page. 404 ");
                break;
            default:
                Assert.fail("Connection Error. " + response.getStatusLine().getStatusCode() + " : "
                        + response.getStatusLine().getReasonPhrase());
                break;
            }
        } catch (IOException e) {
            Assert.fail("IOException: " + e.getMessage());
        }
        return null;
    }

    /**
     * 1?.
     * ??????null??
     * @return ???????
     */
    protected final JSONObject waitForEvent() {
        return waitForEvent(WAIT_FOR_EVENT);
    }

    /**
     * ?????.
     * ??????null??
     * @param time ?
     * @return ???????
     */
    protected final JSONObject waitForEvent(long time) {
        StringBuilder sb = new StringBuilder();
        sb.append("ws://localhost:4035/websocket");

        final JSONObject[] response = new JSONObject[1];
        URI uri = URI.create(sb.toString());
        WebSocketClient client = new WebSocketClient(uri) {
            @Override
            public void onOpen(final ServerHandshake handshake) {
                try {
                    JSONObject root = new JSONObject();
                    root.put(DConnectMessage.EXTRA_SESSION_KEY, getClientId());
                    send(root.toString());
                } catch (JSONException e) {
                    return; // do nothing.
                }
            }

            @Override
            public void onMessage(final String message) {
                try {
                    response[0] = new JSONObject(message);
                } catch (JSONException e) {
                    response[0] = null;
                }
                synchronized (mLockObj) {
                    mLockObj.notify();
                }
            }

            @Override
            public void onError(final Exception ex) {
                synchronized (mLockObj) {
                    mLockObj.notify();
                }
            }

            @Override
            public void onClose(final int code, final String reason, final boolean remote) {
                synchronized (mLockObj) {
                    mLockObj.notify();
                }
            }
        };
        client.connect();

        // ???
        try {
            synchronized (mLockObj) {
                mLockObj.wait(time);
            }
        } catch (InterruptedException e) {
            return response[0];
        } finally {
            // websocket?????
            if (client != null) {
                client.close();
            }
        }
        return response[0];
    }

    /**
     * result??{@link DConnectMessage#RESULT_OK}??????.
     * 
     * @param response ?
     * @throws JSONException JSON??????
     */
    protected static void assertResultOK(final JSONObject response) throws JSONException {
        assertResult(DConnectMessage.RESULT_OK, response);
    }

    /**
     * result??{@link DConnectMessage#RESULT_ERROR}??????.
     * 
     * @param response ?
     * @throws JSONException JSON??????
     */
    protected static void assertResultError(final JSONObject response) throws JSONException {
        assertResult(DConnectMessage.RESULT_ERROR, response);
    }

    /**
     * result??{@link DConnectMessage#RESULT_ERROR}??????.
     * 
     * @param errorCode ?
     * @param response ?
     * @throws JSONException JSON??????
     */
    protected static void assertResultError(final int errorCode, final JSONObject response) throws JSONException {
        assertResult(DConnectMessage.RESULT_ERROR, response);
        assertErrorCode(errorCode, response);
    }

    /**
     * result??????????.
     * 
     * @param expected ?result?
     * @param response ?
     * @throws JSONException JSON??????
     */
    protected static void assertResult(final int expected, final JSONObject response) throws JSONException {
        Assert.assertTrue(response.has(DConnectMessage.EXTRA_RESULT));
        int actual = response.getInt(DConnectMessage.EXTRA_RESULT);
        if (expected != actual) {
            String message = "expected result=" + expected + " but actual result=" + actual + ". "
                    + response.toString();
            fail(message);
        }
    }

    /**
     * ??????????.
     * 
     * @param expectedCode ?
     * @param actualResponse ??
     * @throws JSONException JSON??????
     */
    private static void assertErrorCode(final int expectedCode, final JSONObject actualResponse)
            throws JSONException {
        if (!actualResponse.has(DConnectMessage.EXTRA_ERROR_CODE)) {
            fail("actualResponse is not a error response: " + actualResponse.toString());
        }
        int actualCode = actualResponse.getInt(DConnectMessage.EXTRA_ERROR_CODE);
        if (expectedCode != actualCode) {
            String message = "expected=<" + expectedCode + "> but actual=<" + actualCode + ">: "
                    + actualResponse.toString();
            fail(message);
        }
    }

    /**
     * ??????.
     * @author NTT DOCOMO, INC.
     */
    protected class BinaryBody extends AbstractContentBody {
        /** ??. */
        private String mFileName;
        /** ???. */
        private byte[] mBuffer;

        /**
         * .
         * @param buf ?
         * @param fileName ??
         */
        public BinaryBody(final byte[] buf, final String fileName) {
            super(fileName);
            mBuffer = buf;
            mFileName = fileName;
        }

        @Override
        public String getFilename() {
            return mFileName;
        }

        @Override
        public String getCharset() {
            return "UTF-8";
        }

        @Override
        public long getContentLength() {
            return mBuffer.length;
        }

        @Override
        public String getTransferEncoding() {
            return "UTF-8";
        }

        @Override
        public void writeTo(final OutputStream out) throws IOException {
            out.write(mBuffer);
        }
    }
}