BaseSpace Java SDK

Table of Contents

BaseSpace Java SDK

  1. Purpose
  2. Obtaining the Java SDK for BaseSpace
  3. Setting Up the Development Environment
  4. Getting Your Client Id and Client Secret
  5. Create Your First Java BaseSpace Application

    • Triggering From BaseSpace, Authentication, and Accessing User Data
      • Notes Regarding Triggering
    • The ApiConfiguration Interface
    • Providing Your Implementation of ApiConfiguration
    • Create a New Test Application class with a main method
    • Create an instance of the ApiClient by passing the configuration to the ApiClientManager
    • Run the project
    • A Note About Authentication
  6. Conventions Used in the SDK
    • Noteworthy Resources
    • Retrieving a Response from a BaseSpace API call
      • Single Object Response
      • Array of objects Response
    • Compact Entity vs. Full Entity
    • Query Parameters
  7. Example Operations in the SDK
    • Get the Current User
    • Get the first 10 Projects Associated with the Current User and Load the Full Entity for Each
    • Get the first 10 AppResults for a Project and list the first 10 .bam and .vcf files within each appresult:
    • Download the first 5 Appresult .vcf files to a local folder:
  8. Writing Back to BaseSpace
    • Creating a New Project for the Current User
    • Creating a New AppResult Within the Project
    • Uploading File To AppResult
  9. Properties
    • Adding Properties to an Entity

Purpose

BaseSpace offers a Java SDK for developers. It is used for BaseSpace application development and script development for Illumina’s cloud-based solution for next-generation sequencing analysis.

This SDK has the ability to authenticate an app, gain access to use data, and upload analysis back to BaseSpace. The purpose of this SDK is to provide easy-to-use methods and a strongly typed data model representing BaseSpace concepts in Java without having to deal directly with the JSON over HTTP BaseSpace API directly.

Obtaining the Java SDK for BaseSpace

The BaseSpace Java SDK is available on GitHub and can be cloned by issuing the following Git command:

git clone git@github.com:basespace/basespace-java-sdk.git

Or a developer can go to:

https://github.com/basespace/basespace-java-sdk/

and download the BaseSpace Java SDK. This SDK will include all of the classes in the SDK as well as a few dependency .jar files For more detailed information, please read over the BaseSpace Java SDK Documentation.  

Setting Up the Development Environment

The following steps must be performed when configuring a development environment for the BaseSpace Java SDK. These instructions assume the Eclipse IDE, but the project/dependency configuration can be mapped to the Java IDE of your choice:

Setting Up The Development Environment
Step Instructions
1. Install Eclipse The most common IDE for Java is Eclipse. Eclipse can be downloaded here. This particular version of Eclipse has Maven integration, which will automatically include dependencies that the SDK will need to compile.
2. Create a project In Eclipse, go to the Workbench. Then we click on File -> New -> Java Project. This will take us to another screen where we can name our project and specify the JRE, we choose the default (or most up-to-date) values and name our project.
3a. Include the Java SDK Package (Method 1) In the first method, we navigate to the location of the basespace-java-sdk using our computer's file explorer. We then further navigate to src -> main -> java. Here we should have the "com" folder. We can simply drag and drop this folder to the "src" folder in our Eclipse Project. Eclipse will ask whether to copy these files or create links, this step is up to the developer. Now, under "src" we should have a package called com.illumina.basespace with all of the classes listed under it.
3b. Include the Java SDK Package (Method 2) Using the second method, we first right click on src in our Project. Select New -> Package. This will bring up a box where we specify where to put the package and what to name it. Name this package com.illumina.basespace. This package should appear in the src of the Project. Now, we use our computer's file explorer to navigate to basespace-java-sdk -> src -> main -> java -> com -> illumina -> basespace. In this folder we see all of the classes listed. Simply select all of these classes and drag and drop them into the com.illumina.basespace package.
4. Add the jar files to the Project (Note: Maven will automatically include these for us) In the Package Explorer on the left side of Eclipse, we right click on the project that was just created and select Build Path -> Configure Build Path. This will take us to the Java Build Path. Here we click on Add External JARs then navigate to and select the five .jar files that are included with the Java SDK. The dependencies for this SDK are the following .jar files:
  • jackson-annotations-2.0.1.jar
  • jackson-core-2.0.1.jar
  • jackson-databind-2.0.1.jar
  • jersey-client-1.12.jar
  • jersey-core-1.12.jar

We are now ready to begin development using the BaseSpace Java SDK!

Getting Your Client Id and Client Secret

The clientId and clientSecret are unique to your app. They are used as an identifier for the API to know which app is asking for access and to return access specific to them.

Getting the Client Id and Secret
Step Instructions
1. Go to the App Dashboard Go to the App Dashboard in the BaseSpace Developer Portal
2. Create a New Application Click on "Create a new Application". Enter the fields requested. The Home Page URL is the home page of our app which gives information about the app, this is not the redirect URL where we have BaseSpace redirect the user to access and launch our app. Finally, Click "Create Application"
3. Retrieve the client Id and client secret We are now taken to the Details page of our app. The client_id and client_secret are shown here.

Note: Normally these steps would give us the scope that our app would need to request access to a user's data, but let us continue with the assumption that we have the scope defined for us

Create Your First Java BaseSpace Application

Now that our development environment is set up and we have the clientId and clientSecret for our app, we can begin creating our Java application. This guide will show how to create a Sample App.

Triggering From BaseSpace, Authentication, and Accessing User Data

These are the general steps that would occur when triggering an app in BaseSpace: 1. The user launches the application from BaseSpace 2. The user selects which context to run the application in (Projects, AppResults, Samples, etc) 3. The user grants our application access to this data 4. The user is redirected to our redirect uri, and the redirect uri has a query parameter called appsessionuri which contains information about the context from which the user 5. Our application makes a GET call to that appsession id (found in the appsession uri, which looks like v1pre3/appsessions/{appsession id}) 6. The References response field in the appsession will contain information about the context 7. Pull the context information out, it should be a Project, Run, AppResult, or Sample Id 8. Request appropriate access to the resource that the user selected through the scope parameter, an example being read project 1 9. In this case our scope would be read project 1, scope is described in more detail in BaseSpace Permissions.

Notes Regarding Triggering

More Methods will be added to handle application triggering from BaseSpace, currently this SDK does not handle launching from a Project, Sample, AppResult, or Run from BaseSpace. Instead, an application using this SDK would need to request BROWSE GLOBAL as its scope then navigate through user data and request higher access to download or upload data

The ApiConfiguration Interface

ApiConfiguration is a Java interface provided by the SDK which defines the information that must be provided in order for the Java SDK to connect to, authenticate against, and exchange information with the BaseSpace API. Your application must provide an implementation of this interface. Please see the JavaDoc included with the BaseSpace Java SDK for further information regarding the methods of this interface

Providing Your Implementation of ApiConfiguration

For the purpose of this sample application, let us assume that our scope from the previous step was browse global.

Create the Implementation class for ApiConfiguration
Step Instructions
1. Create a new Java package Create a new package in Eclipse for our application by right-clicking on src in our Project -> New -> Package. The name should be of the form com.{identifier1}.{appname}, so for example com.johndoe.testapp.
2. Create a new Java class that implements ApiConfiguration Create a new Class within this Package, call it BaseSpaceTestConfiguration.java, the Class should look like this: public class BaseSpaceTestConfiguration implements ApiConfiguration
3. Import ApiConfiguration into your class Import ApiConfiguration.java from the SDK into BaseSpaceTestConfiguration.java by adding the following above the class name: import com.illumina.basespace.ApiConfiguration; Note: If you used the new class wizard in Eclipse this import would be created automatically

At this point you should have a new class that implements ApiConfiguration. Below is a table of the information you will need to provide for each interface method for this example application.

ApiConfiguration Information To Provide:
Method Value
getApiRootUri() https://api.basespace.illumina.com
getAccessTokenUriFragment() /oauthv2/token
getAuthorizationUriFragment() /oauthv2/deviceauthorization
getVersion() v1pre3
getAuthorizationScope() browse global
getClientId() The client id obtained in the section “Getting Your Client Id and Client Secret”
getClientSecret() The client secret obtained in the section “Getting Your Client Id and Client Secret”

  An example of the full implementation class:

package com.test;
import com.illumina.basespace.ApiConfiguration;
public class BaseSpaceTestConfiguration implements ApiConfiguration
{
    @Override
    public String getVersion()
    {
        return "v1pre3";
    }

    @Override
    public String getClientId()
    {
        return "my client id";//Use the real client id you obtained
    }

    @Override
    public String getClientSecret()
    {
        return "my client secret";//Use the real client secret you obtained
    }

    @Override
    public String getApiRootUri()
    {
        return "https://api.basespace.illumina.com";
    }

    @Override
    public String getAccessTokenUriFragment()
    {
        return "/oauthv2/token";
    }

    @Override
    public String getAuthorizationScope()
    {
        return "browse global";
    }

    @Override
    public String getProxyHost()
    {
        return null;
    }

    @Override
    public int getProxyPort()
    {
        return 0;
    }

    @Override
    public String getAuthorizationUriFragment()
    {
        return "/oauthv2/deviceauthorization";
    }

    @Override
    public String getAccessToken()
    {
        return null;
    }

    @Override
    public int getReadTimeout()
    {
        return 0;
    }

    @Override
    public int getConnectionTimeout()
    {
        return 0;
    }

    @Override
    public String getStoreRootUri()
    {
        return null;
    }
}

Create a New Test Application class with a main method

Create a new class for the test application which will be the entry point with a main() method in the same package. For this example we are naming this class BaseSpaceTestApp. Within the main method create a new instance of the BaseSpaceTestConfiguration class you created in the previous step. Example of the class is provided below:

package com.test;
public class BaseSpaceTestApp
{
    public static void main(String[] args)
    {
        BaseSpaceTestConfiguration config = new BaseSpaceTestConfiguration();
    }
}

Create an instance of the ApiClient by passing the configuration to the ApiClientManager.

The ApiClientManager is a singleton class whose job it is to create new ApiClient objects for a given configuration. The complete code is provided below:

package com.test;
public class BaseSpaceTestApp
{
    public static void main(String[] args)
    {
            BaseSpaceTestConfiguration config = new BaseSpaceTestConfiguration();
    ApiClient client = ApiClientManager.instance().createClient(config);
    }
}

Run the project

If using Eclipse, create a new Run Configuration for your project and select your test application class BaseSpaceTestApp as the startup class. If using a different IDE, please perform the equivalent necessary steps to select a startup class and run the project within that IDE. Now run the project.

A Note About Authentication

The BaseSpace Java SDK follows the OAuth device authentication workflow. The details of the OAuth mechanism is beyond the scope of this document, so for further information about OAuth and how BaseSpace uses it please consult the BaseSpace documentation at: https://developer.basespace.illumina.com/docs/content/documentation/authentication/obtaining-access-tokens#ObtainingAccessTokens Because your ApiConfiguration implementation class provides a client id, client secret, and authorization scope, you must log into the MyIllumina.com website in order for the Java SDK to obtain an access token. The Java SDK will attempt to launch a web browser native to your platform so that you can enter your credentials. Once you have successfully logged in to MyIllumina, the SDK will obtain an access token which will then apply to all subsequent communication with the BaseSpace API through the SDK.

Alternatively, if your access token is known before hand, it can be provided to the getAccessToken() method of your ApiConfiguration implementation class, and the SDK will use that token for access instead of launching a browser and requiring login.

At this point you now have a reference to an instance of ApiClient, so you can now perform operations against the BaseSpace API via the SDK.  

Conventions Used in the SDK

Once you have obtained an instance of ApiClient as outlined in the previous section, you can make calls against the BaseSpace API through the SDK ApiClient class.

Noteworthy Resources

Before getting further into some of the SDK functionality, it is recommended that SDK developers familiarize themselves with some of the following resources:

Noteworthy Resources
Resource Location
The BaseSpace Data Model https://developer.basespace.illumina.com/docs/content/documentation/rest-api/data-model-overview
BaseSpace Java SDK Javadoc Included in distribution

Noteworthy Resources

BaseSpace Java SDK Javadoc Included in distribution

Retrieving a Response from a BaseSpace API call

When the BaseSpace Java SDK makes a call against the BaseSpace API, it serializes its data into the JSON format and de-serializes it back from JSON to strongly typed objects when the response is received. A response can either return a single object or an array of objects.

Single Object Response

The singular version of a response object is named with the following convention:

GetXXXResponse

Where XXX is the entity type of the response. For example:

GetProjectResponse resp = client.getProject("1005");

This response object will contain a single entity which can be obtained with the get() method

Project project = resp.get();

Array of objects Response

The array of objects response is named with the following convention:

ListXXXResponse

Where XXX is the entity type of the response. For example:

ListAppResultsResponse appResultResp = client.getAppResults(project, null);

This response object will contain an array of entities which can be obtained with the items() method

AppResultCompact[]appResults = appResultsResp.items();

Compact Entity vs. Full Entity

A convention used in the BaseSpace API which is represented in the Java SDK is the concept of a compact vs. full entity. For performance reasons, the compact version of an entity has a less information and thus a smaller payload in its response and is typically returned in an array of objects response. If your application requires more information about the entity, it should call the single object method of the SDK to obtain the full entity. In the data model of the SDK, every full version of an entity extends the compact version. The following snippet obtains an array of compact entities and iterates over them, obtaining the full version:  

ListAppResultsResponse appResultsResp = client.getAppResults(project, null);
AppResultCompact[]appResults = appResultsResp.items();
for(AppResultCompact compact:appResults)
{
    AppResult fullAppResult = client.getAppResult(compact.getId()).get();
}

Query Parameters

Typically the ApiClient methods that return an array of objects response will take a QueryParams object as one of its parameters. The QueryParams object is useful for limiting the number and scope of the results. For example you can limit the number of results or specify a starting offset for the results, which is useful if you are implementing a paging table in your application’s UI etc. Passing null as a parameter to a method which expects QueryParams will result in the BaseSpace API falling back to a default number of results, which may or may not be desired.

Example Operations in the SDK

Below are some of the more common operations a developer may perform using the BaseSpace Java SDK with some code examples. All of the examples assume you have already obtained an ApiClient object using the steps outlined in the Create Your First BaseSpace Application section of this document.

Get the Current User

The following example retrieves the current user associated with the access token granted to the ApiClient

User user = client.getCurrentUser().get();
System.out.println("User " + user.getName() + " at email " + user.getEmail());

Get the first 10 Projects Associated with the Current User and Load the Full Entity for Each

ProjectCompact projects[] = client.getProjects(new QueryParams(10)).items();
for(ProjectCompact project:projects)
{
    System.out.println("Project " + project.getName() + " owned by " + project.getUserOwnedBy().getName());
    Project project = client.getProject(projectCompact.getId()).get();
    System.out.println("App results for this project: " + project.getAppResultsHref().toString());
}

Get the first 10 AppResults for a Project and list the first 10 .bam and .vcf files within each appresult:

FileParams fileParams = new FileParams(new String[]{".bam",".vcf"},10); 
AppResultCompact[]appResults = client.getAppResults(project, new QueryParams(10)).items();
for(AppResultCompact appResultCompact:appResults)
{
    FileCompact[]files = client.getFiles(appResultCompact, fileParams).items();
    for(FileCompact file:files)
    {
        System.out.println("Got the file " + file.getName() +" within appresult " + appResultCompact.getName());
    }

}

Download the first 5 Appresult .vcf files to a local folder:

AppResult fullAppResult = client.getAppResult("1093").get();
FileParams fileParams = new FileParams(new String[]{".vcf"},5);
FileCompact[]files = client.getFiles(fullAppResult, fileParams).items();
for(FileCompact fileCompact:files)
{
    //For a download we need the full file entity
    final File file = client.getFile(fileCompact.getId()).get();
    //Local folder for a windows machine. File will be saved here with same name as 
    //BaseSpace file entity
    final java.io.File localFolder = new java.io.File("C:\\BasespaceFiles");
    client.download(file, localFolder, new DownloadListener()
    {
    @Override
    public void progress(DownloadEvent evt)
    {
        System.out.println("We downloaded " + evt.getCurrentBytes() + " of " + evt.getTotalBytes());
    }
    @Override
    public void complete(DownloadEvent evt)
    {
        System.out.println("Download is done");
        assert(new java.io.File(localFolder,file.getName()).exists());
    }
    @Override
    public void canceled(DownloadEvent evt)
    {
    }
    });
}

Writing Back to BaseSpace

To upload results back to BaseSpace, an app would perform the following steps:

  1. Create a new Project in BaseSpace or choose an Existing Project that the User is the Owner of
  2. Create a new AppResult within that Project
  3. Upload Files to the AppResult
  4. Mark the AppSession as Complete

The first step in your app is to choose an output Project for the user’s results to be upload into in BaseSpace. There are two options here, the app can either create a new Project each time or it can allow the user to specify an existing Project in BaseSpace for output that the user is the Owner of.

To check if a user is the owner of a Project, simply check the UserOwnedBy field for that Project to ensure that it matches the currently logged in user’s Id.

In order to create a Project, the app’s access token must include the scope create projects and in order to upload data to an existing Project, the app’s access token must include the scope write project {id}.

Creating a New Project for the Current User

Project item = client.createProject("TestProject created by Java SDK").get();

System.out.println("New ProjectId=" + item.getId());  

Creating a New AppResult Within the Project

AppResult newAppResult = client.createAppResult(project, "TestAppResult","Description",null, null).get();
System.out.println("Created appresult " + newAppResult.getId());

Uploading File To AppResult

The example below shows how to perform a file upload to an appresult. For simplicity of example, we are uploading the entire file in a single part even though multi-part uploads are supported. Please consult BaseSpace documentation for details on the multipart upload functionality.

AppResult appresult = client.getAppResult(“12345”).get();
GetFileResponse resp = client.startMultipartUpload(appresult, "testfile.txt", "text/plain", null);
InputStream is = null;
try
{
    java.io.File toUpload = new java.io.File("C:\\Files\\BasespaceUpload\\testfile.txt");
    is = new FileInputStream(toUpload);
    client.uploadFilePart(resp.get(), 1, null, is);
    is.close();
    is = null;
    client.setMultipartUploadStatus(resp.get(), UploadStatus.Complete);
    File theUploadedFile = client.getFile(resp.get().getId()).get();
    assert(toUpload.length() == theUploadedFile.getSize().longValue());
}
catch(Throwable t)
{
    throw new RuntimeException(t);
}
finally
{
    //Just good practice
    if (is != null) try
    {
    is.close();
    }
    catch (IOException e)
    {
    }
}

Properties

Adding Properties to an Entity

Some BaseSpace entities support properties. Please consult the BaseSpace documentation to learn which specific types support properties. The following example shows the addition of various properties to a project entity:

Create a new property list

List<Property<?>>properties = new ArrayList<Property<?>>();

Add a single string property

properties.add(new StringProperty("mytestapp.metrics.magicnumber","myDesc","42"));

Add an array of strings property

String[]stringArray = new String[]{"item1","item2","item3"};
properties.add(new StringProperty("mytestapp.metrics.magicnumbers","a Description",stringArray));

Add an appresult reference property

AppResult appresult = client.getAppResult(get("appresult.id")).get();
AppResultReference refProp = new AppResultReference("mytestapp.inputs.appresults","AppresultTest",appresult);
properties.add(refProp);

Project project = client.getProject(get("project.id")).get();
ListPropertiesResponse resp =  client.putProperties(project, properties.toArray(new Property[properties.size()]));