Skip to content

Java (Android) OLD

For any developer working with NeuroScale at the API level it is a good idea to create appropriate data structures to simplify interaction with the platform. The following class shown below is a good example and is shown in its entirety for those eager to get going with sample code.

/**
 * NeuroScale.java
 * Copyright (c) 2015 by Syntrogi, Inc.
 */

package com.syntrogi.brainstreamer;

import android.content.Context;

import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.ResponseHandlerInterface;
import com.syntrogi.brainstreamer.exception.NeuroScaleException;
import com.syntrogi.brainstreamer.mqtt.MqttBrokerAddress;
import com.syntrogi.brainstreamer.mqtt.MqttTopicNames;

import org.apache.http.Header;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class NeuroScale {
    public static final String CREATE_INSTANCE_REQUEST_BODY = "" +
        "{\n" +
        "    \"persist\": {\n" +
        "        \"dataset_in\": false,\n" +
        "        \"dataset_out\": false,\n" +
        "        \"model\": false\n" +
        "    },\n" +
        "    \"pipeline\": \"%s\",\n" +
        "    \"properties\": {\n" +
        "        \"%s\": \"%s\",\n" +
        "        \"%s\": \"%s\",\n" +
        "        \"%s\": \"%s\",\n" +
        "        \"%s\": false\n" +
        "    }\n" +
        "}";

    protected String apiUrl;
    protected String apiVersion;
    protected String accessToken;
    protected static NeuroScale instance = null;    // Singleton.

    protected NeuroScale( String apiUrl, String apiVersion, String accessToken ) {
        this.apiUrl = apiUrl;
        this.apiVersion = apiVersion;
        this.accessToken = accessToken;
    }

    public static NeuroScale getInstance() {
        if( NeuroScale.instance == null ) {
            NeuroScale.instance = new NeuroScale(
                BrainStreamerSettings.API_URL,
                BrainStreamerSettings.API_VERSION,
                BrainStreamerSettings.ACCESS_TOKEN
            );
        }

        return NeuroScale.instance;
    }

    public void createInstance( Context ctx, String requestBody, ResponseHandlerInterface responseHandler ) throws NeuroScaleException {
        Header[] headers = {
            new BasicHeader( "Content-Type", "application/json" ),
            new BasicHeader( "Authorization", this.getAuthorizationHeader() )
        };

        AsyncHttpClient client = new AsyncHttpClient();
        client.setTimeout( 30000 );

        try {
            client.post( ctx, this.getInstancesUrl(), headers, new StringEntity( requestBody ), null, responseHandler );
        } catch( UnsupportedEncodingException e ) {
            throw new NeuroScaleException( e );
        }
    }

    public void createTaggedInstance( Context ctx, String playerName, ResponseHandlerInterface responseHandler ) throws NeuroScaleException {
        String requestBody = String.format(
            NeuroScale.CREATE_INSTANCE_REQUEST_BODY,
            BrainStreamerSettings.PIPELINE,
            BrainStreamerSettings.APPLICATION_TAG_NAME,
            BrainStreamerSettings.APPLICATION_TAG_VALUE,
            BrainStreamerSettings.PLAYER_TAG_NAME,
            playerName,
            BrainStreamerSettings.DEVICE_TAG_NAME,
            BrainStreamerInstallation.getId( ctx ),
            BrainStreamerSettings.ACTIVE_TAG_NAME
        );

        this.createInstance( ctx, requestBody, responseHandler );
    }

    public void deleteInstance( Context ctx, String id, ResponseHandlerInterface responseHandler ) throws NeuroScaleException {
        Header[] headers = {
            new BasicHeader( "Authorization", this.getAuthorizationHeader() )
        };

        AsyncHttpClient client = new AsyncHttpClient();
        client.setTimeout( 30000 );
        client.delete( ctx, this.getInstanceUrl( id ), headers, responseHandler );
    }

    public void getInstance( Context ctx, String id, ResponseHandlerInterface responseHandler ) throws NeuroScaleException {
        Header[] headers = {
            new BasicHeader( "Authorization", this.getAuthorizationHeader() )
        };

        AsyncHttpClient client = new AsyncHttpClient();
        client.setTimeout( 30000 );
        client.get( ctx, this.getInstanceUrl( id ), headers, null, responseHandler );
    }

    public void getInstances( Context ctx, ResponseHandlerInterface responseHandler ) throws NeuroScaleException {
        Header[] headers = {
                new BasicHeader( "Authorization", this.getAuthorizationHeader() )
        };

        AsyncHttpClient client = new AsyncHttpClient();
        client.setTimeout( 30000 );
        client.get( ctx, this.getInstancesUrl(), headers, null, responseHandler );
    }

    public List<JSONObject> getInstancesByTagName( List<JSONObject> instances, String tagName ) throws NeuroScaleException {
        instances = new ArrayList<>( instances );

        Iterator<JSONObject> iterator = instances.iterator();

        while( iterator.hasNext() ) {
            try {
                JSONObject properties = iterator.next().getJSONObject( "properties" );

                if( !properties.has( tagName ) ) {
                    iterator.remove();
                }
            } catch( JSONException e ) {
                throw new NeuroScaleException( e );
            }
        }

        return instances;
    }

    public List<JSONObject> getInstancesByTagValue( List<JSONObject> instances, String tagName, String tagValue ) throws NeuroScaleException {
        instances = new ArrayList<>( instances );

        Iterator<JSONObject> iterator = instances.iterator();

        while( iterator.hasNext() ) {
            if( !this.getInstanceTagValue( iterator.next(), tagName ).equals( tagValue ) ) {
                iterator.remove();
            }
        }

        return instances;
    }

    public String getInstanceTagValue( JSONObject instance, String tagName ) throws NeuroScaleException {
        try {
            JSONObject properties = instance.getJSONObject( "properties" );
            return properties.getString( tagName );
        } catch( JSONException e ) {
            throw new NeuroScaleException( e );
        }
    }

    public boolean getInstanceTagFlag( JSONObject instance, String tagName ) throws NeuroScaleException {
        try {
            JSONObject properties = instance.getJSONObject( "properties" );
            return properties.getBoolean( tagName );
        } catch( JSONException e ) {
            throw new NeuroScaleException( e );
        }
    }

    public MqttBrokerAddress getMqttBrokerAddress( JSONObject instance ) throws NeuroScaleException {
        try {
            JSONObject endpoints = instance.getJSONObject( "endpoints" );
            JSONArray data = endpoints.getJSONArray( "data" );
            JSONObject endpoint = data.getJSONObject( 0 );    // Assume all endpoints share the same MQTT broker.

            URL url = new URL( endpoint.getString( "url" ).replace( "mqtt", "http" ) );

            return new MqttBrokerAddress( url.getHost(), url.getPort() );
        } catch( Exception e ) {
            throw new NeuroScaleException( e );
        }
    }

    public MqttTopicNames getMqttTopicNames( JSONObject instance ) throws NeuroScaleException {
        try {
            JSONObject endpoints = instance.getJSONObject( "endpoints" );
            JSONArray data = endpoints.getJSONArray( "data" );

            String readTopicName = null, writeTopicName = null;

            for( int i = 0; i < data.length(); i++ ) {
                JSONObject endpoint = data.getJSONObject( i );

                if( endpoint.getString( "mode" ).equals( "read" ) ) {
                    readTopicName = new URL( endpoint.getString( "url" ).replace( "mqtt", "http" ) ).getPath();
                } else {
                    writeTopicName = new URL( endpoint.getString( "url" ).replace( "mqtt", "http" ) ).getPath();
                }
            }

            return new MqttTopicNames( readTopicName, writeTopicName );
        } catch( Exception e ) {
            throw new NeuroScaleException( e );
        }
    }

    public String getApiUrl() {
        return this.apiUrl;
    }

    public String getApiVersion() {
        return this.apiVersion;
    }

    public String getAccessToken() {
        return this.accessToken;
    }

    public String getInstancesUrl() {
        return this.getApiUrl() + "/" + this.getApiVersion() + "/instances";
    }

    public String getInstanceUrl( String id ) {
        return this.getInstancesUrl() + "/" + id;
    }

    public String getAuthorizationHeader() {
        return "Bearer " + this.getAccessToken();
    }
}

Ok, so there looks to be a lot here but again breaking it down we see a direct mapping between resources and RESTful concepts and Java methods here. We also see sensible management of the many strings (metadata, access tokens, etc) required for proper interaction with NeuroScale. In the sections below we will draw attention to code snippets from above which are particularly important to understand.

Important Strings

From lines 30-45 we have a number of fields used to conveniently manage strings important for interaction with the API. You should recognise the CREATE_INSTANCE_REQUEST_BODY form the cURL tutorial. You will notice that JSON representation in Java at the string level is not the prettiest thing in the world. Once

// Extracted from the full sample at the begining of this document ...

public static final String CREATE_INSTANCE_REQUEST_BODY = "" +
        "{\n" +
        "    \"persist\": {\n" +
        "        \"dataset_in\": false,\n" +
        "        \"dataset_out\": false,\n" +
        "        \"model\": false\n" +
        "    },\n" +
        "    \"pipeline\": \"%s\",\n" +
        "    \"properties\": {\n" +
        "        \"%s\": \"%s\",\n" +
        "        \"%s\": \"%s\",\n" +
        "        \"%s\": \"%s\",\n" +
        "        \"%s\": false\n" +
        "    }\n" +
        "}";

    protected String apiUrl;
    protected String apiVersion;
    protected String accessToken;
    protected static NeuroScale instance = null;    // Singleton.

// ....

The constructor then can be used for initialising these as required

protected NeuroScale( String apiUrl, String apiVersion, String accessToken ) {
        this.apiUrl = apiUrl;
        this.apiVersion = apiVersion;
        this.accessToken = accessToken;
    }

Http client

In order to interact with the NeuroScale API you will need to be able to generate appropriate http requests and handle the corresponding responses. There are several http libraries that one can use but in this example we use an asynchronous callback-based HTTP client for Android developed by James Smith. This client is built on Apache’s HttpClient libraries which are also fine to use in this case. The advantages of the library we use is that all requests are made outside your applications’s main UI thread. Further, the callbacks are executed on the same thread where they were created (using Android’s Handler message passing). For more information please see this link. We can then make http calls to interact with NeuroScale and handle the responses. This is shown below which is an excerpt from the full code listing at the start of this document.

public void createInstance( Context ctx, String requestBody, ResponseHandlerInterface responseHandler ) throws NeuroScaleException {
        Header[] headers = {
            new BasicHeader( "Content-Type", "application/json" ),
            new BasicHeader( "Authorization", this.getAuthorizationHeader() )
        };

        AsyncHttpClient client = new AsyncHttpClient();
        client.setTimeout( 30000 );

        try {
            client.post( ctx, this.getInstancesUrl(), headers, new StringEntity( requestBody ), null, responseHandler );
        } catch( UnsupportedEncodingException e ) {
            throw new NeuroScaleException( e );
        }
    }

This method corresponds to the cURL post request we saw earlier (reproduced below), although the specific pipeline, access token and URL for the API have not been explicitly shown in the Java above.

curl -i -H 'Content-Type: application/json' -H 'Authorization: Bearer ab85d4de-ba8d-4dda-9d31-b7a15fb7372b' -X POST -d '{"persist":{"dataset_in":false,"dataset_out":false,"model":false},"pipeline":"pl_nZcKxcLPkmpcPCskUcbRAZ"}' https://api.neuroscale.io/v1/instances