Here, we will explain how to use the functionalities the CloudRail SI Java SDK provides.

We assume you have already installed the library, if not, have a look at Installation.

The code samples that come with each function description assume that a service that implements the respective interface has already been instantiated.

If you want to run the code samples refer to Services to find instructions on how to instantiate your service and then come back here.

General

In order to understand what functionality which service offers we need to understand the concept of interfaces and implementing services.

CloudRail SI's services all implement one or multiple of the following interfaces:

Name What is does Implementing services
Cloud Storage Upload, download, copy, delete, move, create and get information about files and/or folders in a CloudStorage provider Dropbox, Google Drive, OneDrive, OneDrive Business, Box, Egnyte
Business Cloud Storage Upload and download files, create and delete buckets, list buckets and files, get information about files Amazon S3, Microsoft Azure, Backblaze, Rackspace
Social Profile Retrieve information about a user, including an identifier to realize "Login with ..." Facebook, GitHub, Google+, LinkedIn, Slack, Twitter, Windows Live, Yahoo, Instagram
Social Interaction Retrieve a list of connections/friends/etc and post an update Facebook, FacebookPages, Twitter
Payment Manage charges, refunds and subscriptions of clients who make payments with their credit card to an account on the respective service PayPal, Stripe
Email Programmatically send text/HTML emails to one or many addresses Mailjet, SendGrid
SMS Programmatically send SMS to phones Twilio, Nexmo
Points of Interest Get a list of points of interest in around a given location in a certain radius filtered by search terms and/or categories Google Places, Foursquare, Yelp

Each interface comes with a set of functionalities and implementing that interface implies that the respective service supports all the functionality from that interface.

Interfaces

Cloud Storage

Introduction

The CloudStorage interface bundles functionality around interaction with cloud storage providers. Its main challenge consists in abstracting about how files and folders are referenced. For the sake of easy usage, we have chosen paths over identifiers. This means every file and folder will be referenced by its full path starting at the root folder for all the functions in this interface.

For example, /TestFolder/UserData.csv refers to a file called UserData.csv residing in the TestFolder folder which in turn is located at root.

Implementing services

Function Overview

Did not find the function you need? Try Advanced Request!

Functions

Upload

Declaration
/**
 * Uploads a file to a cloud storage, throws an exception if the path is invalid,
 * the parent path does not exist, the stream is null or the size negative.
 *
 * @param filePath The path where to store the file from the root folder and including the name, e.g /myFolder/myFile.jpg.
 * @param stream A stream from which the file can be read.
 * @param size The size in bytes of the data that can be read from the stream.
 * @param overwrite If true, an existing file with the same path will be overwritten (its contents updated),
 *                  if false the presence of a file with the same name will cause an exception.
 */
void upload(String filePath, InputStream stream, long size, boolean overwrite);
Example
// Loads a file from the resources and uploads it
InputStream stream = null;
try {
    stream = getClass().getResourceAsStream("Data.csv");
    long size = new File(getClass().getResource("Data.csv").toURI()).length();
    cs.upload("/TestFolder/Data.csv", stream, size, false);
} catch (Exception e) {
    // TODO: handle error
} finally {
    // TODO: close stream
}

Download

Declaration
/**
 * Downloads a file from a cloud storage, throws an exception if the file is not
 * found or the path invalid.
 *
 * @param filePath  The path to the file from the root folder and including the
 *                  name, e.g /myFolder/myFile.jpg.
 * @return A stream from which the file can be read.
 */
InputStream download(String filePath);
Example
// Gets an InputStream which can then be written to disk, uploaded somewhere else etc.
InputStream stream = cloudstorage.download("/TestFolder/Data.csv");

Create Folder

Declaration
/**
 * Creates a folder at the given path, throws an exception if the path is invalid
 * or the parent path does not exist.
 *
 * @param folderPath    The path to the folder from the root folder and including
 *                      the name, e.g. /myNewFolder
 */
void createFolder(String folderPath);
Example
cloudstorage.createFolder("/TestFolder");

Copy

Declaration
/**
 * Copies a file from one path in the cloud storage to another, throws an exception
 * if one of the paths is invalid, the source path or the parent destination path
 * does not exist.
 *
 * @param sourcePath The path of the origin file from the root folder and including the name.
 * @param destinationPath   The path of the destination file from the root folder
 *                          and including the name.
 */
void copy(String sourcePath, String destinationPath);
Example
cloudstorage.copy("/TestFolder/Data.csv", "/CopyFolder/Data.csv");

Delete

Declaration
/**
 * Deletes a file or folder from the cloud storage, throws an exception if the
 * path is invalid or does not exist.
 *
 * @param filePath The path to the file to be deleted from the root folder and including the name.
 */
void delete(String filePath);
Example
cloudstorage.delete("/TestFolder/UserData.csv");

Move

Declaration
/**
 * Moves a file or a folder in the cloud storage, throws an exception if one of
 * the paths is invalid, the source path or the parent destination path does not exist.
 *
 * @param sourcePath    The path to the file which should be moved from the root
 *                      folder and including the name.
 * @param destinationPath   The path to move the file to from the root folder and
 *                          including the name.
 */
void move(String sourcePath, String destinationPath);
Example
cloudstorage.move("/TestFolder/Data.csv", "/CopyFolder/Data.csv");

Get Metadata

Declaration
/**
 * Gets metadata about the file/folder, throws an exception if the path is invalid
 * or does not exist. Also throws if getting metadata from root ("/") is attempted!
 *
 * @param filePath The path to the file from the root folder and including the name.
 * @return A container for metadata.
 */
CloudMetaData getMetadata(String filePath);

public class CloudMetaData {

    // The complete path to the file/folder
    private String path;

    // The name of the file/folder
    private String name;

    // The size of the file/folder
    private int size;

    // If is a folder is set to true
    private boolean folder;

    // The last modified date as a timestamp
    private Long modifiedAt;

    // Image metadata if available
    private ImageMetaData imageMetaData;
}

public class ImageMetaData {

    // Image height
    private Long height;

    // Image width
    private Long width;
}
Example
CloudMetaData meta = cloudstorage.getMetadata("/TestFolder/Data.csv");
System.out.println("File size is " + meta.getSize());

Get Children

Declaration
/**
 * Gets the metadata of this folder's children, throws an exception if the path
 * is invalid or does not exist.
 *
 * @param folderPath The path to the file from the root folder and including the name.
 * @return A list of metadata, one entry for every child.
 */
List<CloudMetaData> getChildren(String folderPath);

public class CloudMetaData {

    // The complete path to the file/folder
    private String path;

    // The name of the file/folder
    private String name;

    // The size of the file/folder
    private int size;

    // If is a folder is set to true
    private boolean folder;

    // The last modified date as a timestamp
    private Long modifiedAt;

    // Image metadata if available
    private ImageMetaData imageMetaData;
}

public class ImageMetaData {

    // Image height
    private Long height;

    // Image width
    private Long width;
}
Example
List<CloudMetaData> metas = cloudstorage.getChildren("/TestFolder");
System.out.println("Folder has " + metas.size() + " children");

Get Children Page

Declaration
/**
 * Gets the metadata of this folder's children in chunks, throws an exception if the path is invalid or does not exist
 * Returns an empty array if offset or limit get out of bounds of existing children
 *
 * @param folderPath The path to the file from the root folder and including the name
 * @param offset The offset for the children
 * @param limit The amount of children returned
 * @return A list of containers for metadata
 */
List<CloudMetaData> getChildrenPage(String folderPath, long offset, long limit);

public class CloudMetaData {

    // The complete path to the file/folder
    private String path;

    // The name of the file/folder
    private String name;

    // The size of the file/folder
    private int size;

    // If is a folder is set to true
    private boolean folder;

    // The last modified date as a timestamp
    private Long modifiedAt;

    // Image metadata if available
    private ImageMetaData imageMetaData;
}

public class ImageMetaData {

    // Image height
    private Long height;

    // Image width
    private Long width;
}
Example
List<CloudMetaData> metas = cloudstorage.getChildrenPage("/TestFolder", 0, 10);
if (metas.size() == 10) {
    System.out.println("Successfully retrieved the first 10 children");
}

Create Share Link

Declaration
/**
* Creates a share link and the permission is only to 'view' and download the file/folder
*
* @param path the path to the file/folder which the link to will be created
* @return The url as a String
*/
String createShareLink(String path);
Example
String shareLink = cloudstorage.createShareLink("/TestFolder");
System.out.println("The share link is " + shareLink);

Get Allocation

Declaration
/**
*
* @return The total space in bytes and the used space
*/
SpaceAllocation getAllocation();

public class SpaceAllocation {
    //The used space in bytes
    private Long used;

    //The available space in bytes
    private Long total;
}
Example
SpaceAllocation allocation = cloudstorage.getAllocation();
System.out.println("The total space is " + allocation.getTotal() + " The used space is "+ allocation.getUsed());

Exists

Declaration
/**
 * Checks if a given path already exists on a users storage.
 *
 * @param path The path that shall be checked.
 * @return True if the file / folder exists, false otherwise.
 */
boolean exists(String path);
Example
if (!cloudstorage.exists("/AppFolder")) {
    cloudstorage.createFolder("/AppFolder");
}

Get Thumbnail

Declaration
/**
 * Return a thumbnail if there is one available.
 *
 * @param path File path.
 * @return Thumbnail if present, null otherwise.
 * @throws com.cloudrail.si.exceptions.NotFoundException Is thrown if there is no file at the
 *                                                       provided path.
 * @throws IllegalArgumentException                      Is thrown if the passed path is invalid or null.
 * @throws com.cloudrail.si.exceptions.HttpException     Is thrown if something goes wrong while
 *                                                       communicating with the service.
 */
InputStream getThumbnail(String path);
Example
InputStream thumb = cloudstorage.getThumbnail("/image.jpeg");

Get User's Login Identifier

Declaration
/**
 * @return The currently logged in user's login identifier (name/email/...).
 */
String getUserLogin();
Example
String login = cloudstorage.getUserLogin();

Get User's Name

Declaration
/**
 * @return The currently logged in user's (full) name
 */
String getUserName();
Example
String name = cloudstorage.getUserName();

Explicit Login

Declaration
/**
 * Optional! Explicitly triggers user authentication.
 * Allows better control over the authentication process.
 * Optional because all methods that require prior authentication will
 * trigger it automatically, unless this method has been called before.
 */
void login();
Example
cloudstorage.login();

Explicit Logout

Declaration
/**
 * Optional! Revokes the current authentication.
 */
void logout();
Example
cloudstorage.logout();

Save As String

Declaration
/**
 * A method to retrieve the data from a service that is intended for
 * persistent storage.
 *
 * @return The data of the service that should be stored persistently,
 * e.g. access credentials.
 */
String saveAsString();
Example
// Assume cs and cs2 are both instances of the same service
// cs already has a logged in user and cs2 is freshly created
String data = cs.saveAsString();
cs2.loadAsString(data);
// Now cs2 has the same user logged in as cs

Load As String

Declaration
/**
 * Loads/restores data saved by saveAsString() into the service.
 *
 * @param savedData The persistent data that was stored.
 */
void loadAsString(String savedData);
Example
// Assume cs and cs2 are both instances of the same service
// cs already has a logged in user and cs2 is freshly created
String data = cs.saveAsString();
cs2.loadAsString(data);
// Now cs2 has the same user logged in as cs

Business Cloud Storage

Introduction

This is a common interface for Bucket based Cloud Storage Services. Instead of organizing files in nested folders, they reside in a bucket.

Implementing services

Function Overview

Functions

List Buckets

Declaration
/**
 * Get a list of all buckets within your account.
 *
 * @return List of buckets. This might be an empty list if there are now buckets.
 */
List<Bucket> listBuckets();

public class Bucket {
    private String name;
    private String identifier;
}
Example
List<Bucket> buckets = storage.listBuckets();
System.out.println("You own " + buckets.size() + " buckets");

Create Bucket

Declaration
/**
 * Creates a new empty bucket.
 *
 * @param name The name of the new bucket.
 * @return The newly created bucket.
 * @throws IllegalArgumentException Is thrown if a bucket with the same name already exists.
 */
Bucket createBucket(String name);

public class Bucket {
    private String name;
    private String identifier;
}
Example
Bucket bucket = storage.createBucket("bucketname");
System.out.println("Bucket: " + bucket.toString());

Delete Bucket

Declaration
/**
 * Deletes the specified bucket with all it's content.
 *
 * @param bucket The bucket which will be deleted.
 * @throws NotFoundException Is thrown if the bucket does not exist.
 */
void deleteBucket(Bucket bucket);

public class Bucket {
    private String name;
    private String identifier;
}
Example
storage.deleteBucket(bucket);
System.out.println("Bucket successfully deleted");

List Files

Declaration
/**
 * Get a list of files contained in the specified bucket.
 *
 * @param bucket The bucket containing the files.
 * @throws NotFoundException Is thrown if the specified bucket does not exist.
 */
List<BusinessFileMetaData> listFiles(Bucket bucket);

public class Bucket {
    private String name;
    private String identifier;
}

public class BusinessFileMetaData {
    private String fileName;
    private String fileID;
    private Long size;
    private Long lastModified;
}
Example
List<BusinessFileMetaData> files = storage.listFiles(bucket);
System.out.println("The bucket named " + bucket.name + " has " + files.length + " files");

Upload File

Declaration
/**
 * Uploads a new file into a bucket or replaces the file if it is already present.
 *
 * @param bucket  The bucket into which the file shall be put.
 * @param name    The name of the file.
 * @param content The file content as an InputStream.
 * @param size    The amount of bytes that the file contains.
 */
void uploadFile(Bucket bucket, String name, InputStream content, long size);

public class Bucket {
    private String name;
    private String identifier;
}
Example
// Loads a file from the resources and uploads it
InputStream stream = null;
try {
    stream = getClass().getResourceAsStream("Data.csv");
    long size = new File(getClass().getResource("Data.csv").toURI()).length();
    storage.upload(bucket, "Data.csv", stream, size);
    System.out.println("Upload successfully finished");
} catch (Exception e) {
    // TODO: handle error
} finally {
    // TODO: close stream
}

Delete File

Declaration
/**
 * Deletes a file within a bucket.
 *
 * @param bucket   The bucket that contains the file.
 * @param fileName The name of the file.
 * @throws NotFoundException Is thrown if there is no file with the given
 *                           name inside the bucket.
 */
void deleteFile(String fileName, Bucket bucket);

public class Bucket {
    private String name;
    private String identifier;
}
Example
storage.deleteFile("Data.csv", bucket);
System.out.println("File successfully deleted");

Download File

Declaration
/**
 * Downloads a file from a bucket.
 *
 * @param bucket   The bucket which contains the file.
 * @param fileName The name of the file.
 * @return The content of the file as an InputStream.
 * @throws NotFoundException Is thrown if there is no file with the given
 *                           name inside the bucket.
 */
InputStream downloadFile(String fileName, Bucket bucket);

public class Bucket {
    private String name;
    private String identifier;
}
Example
// Gets an InputStream which can then be written to disk, uploaded somewhere else etc.
InputStream stream = storage.downloadFile("UserData.csv", bucket);
System.out.println("Download successful!");

Get File Metadata

Declaration
/**
 * Get metadata of a file containing the name, the size and the last
 * modified date.
 *
 * @param bucket   The bucket where the file is located.
 * @param fileName The name of the file.
 */
BusinessFileMetaData getFileMetadata(Bucket bucket, String fileName);

public class Bucket {
    private String name;
    private String identifier;
}

public class BusinessFileMetaData {
    private String fileName;
    private String fileID;
    private Long size;
    private Long lastModified;
}
Example
BusinessFileMetaData meta = storage.getFileMetadata(bucket, "Data.csv");
System.out.println("The file " + meta.name + " is " + meta.size / 1000 + " kilobytes big");

Social Profiles

Introduction

The Profile interface is a common interface for Services that provide unique user identifiers and general user information.

With the getIdentifier function, "Login with ..." scenarios can be easily implemented: Whenever a user needs to login/signup, call the getIdentifier function of an instance of this interface. This will have the user login and then return a unique identifier for this user with this service. Use this to identify a user's account with your application.

All the other information might be present or not, depending on the service and how much information the user has filled out with the respective service. To avoid unnecessary requests, information is cached up to one minute.

Implementing services

Function Overview

Did not find the function you need? Try Advanced Request!

Functions

Get Identifier

Declaration
/**
 * @return   A unique identifier for the authenticated user.
 *           All services provide this value. Useful for "Login with ...".
 *           Prefixed with the lowercased service name and a minus.
 */
String getIdentifier();
Example
String id = profile.getIdentifier();

Get Full Name

Declaration
/**
 * @return The user's full name or null if not present.
 */
String getFullName();
Example
String name = profile.getFullName();

Get Email

Declaration
/**
 * @return The user's email address or null if not present.
 */
String getEmail();
Example
String email = profile.getEmail();

Get Gender

Declaration
/**
 * @return  The user's gender, normalized to be one of "female", "male",
 *          "other" or null if not present.
 */
String getGender();
Example
String gender = profile.getGender();

Get Description

Declaration
/**
 * @return The description the user has given themselves or null if not present.
 */
String getDescription();
Example
String description = profile.getDescription();

Get Date Of Birth

Declaration
/**
 * @return The date of birth in a special format.
 */
DateOfBirth getDateOfBirth();

public class DateOfBirth {
    private Long year;
    private Long month;
    private Long day;
}
Example
DateOfBirth dob = profile.getDateOfBirth();
String germanDate =
    (dob.getDay() != null ? dob.getDay() : "?") + "." +
    (dob.getMonth() != null ? dob.getMonth() : "?") + "." +
    (dob.getYear() != null ? dob.getYear() : "?");

Get Locale

Declaration
/**
 * @return The locale/language setting of the user, e.g. "en", "de" or null if not present.
 */
String getLocale();
Example
String locale = profile.getLocale();

Get Picture URL

Declaration
/**
 * @return The URL of the user's profile picture or null if not present.
 */
String getPictureURL();
Example
String pictureURL = profile.getPictureURL();

Explicit Login

Declaration
/**
* Optional! Explicitly triggers user authentication.
* Allows better control over the authentication process.
* Optional because all methods that require prior authentication will
* trigger it automatically, unless this method has been called before.
*/
void login();
Example
profile.login();

Explicit Logout

Declaration
/**
* Optional! Revokes the current authentication.
*/
void logout();
Example
profile.logout();

Save As String

Declaration
/**
* A method to retrieve the data from a service that is intended for
* persistent storage.
*
* @return The data of the service that should be stored persistently,
* e.g. access credentials.
*/
String saveAsString();
Example
// Assume profile and profile2 are both instances of the same service
// profile already has a logged in user and profile2 is freshly created
String data = profile.saveAsString();
profile2.loadAsString(data);
// Now profile2 has the same user logged in as profile

Load As String

Declaration
/**
* Loads/restores data saved by saveAsString() into the service.
*
* @param savedData The persistent data that was stored.
*/
void loadAsString(String savedData);
Example
// Assume profile and profile2 are both instances of the same service
// profile already has a logged in user and profile2 is freshly created
String data = profile.saveAsString();
profile2.loadAsString(data);
// Now profile2 has the same user logged in as profile

Social Interaction

Introduction

This is a common interface for services that provide a set of social functionalities. Currently the functionalities are limited to receiving a list of user ids with which the currently logged in user has a connection to and who is also using your app and to post an update to a users timeline.

Implementing services

Function Overview

Functions

Get Connections

Declaration
/**
 * Retrieves a list of connection/friend/etc. IDs.
 * The IDs are compatible with those returned by Profile.getIdentifier().
 *
 * @return A (possibly empty) list of IDs.
 */
List<String> getConnections();
Example
List<String> connections = social.getConnections();

Post Update

Declaration
/**
 * Creates a new post/update to the currently logged in user's wall/stream/etc.
 * Throws an exception if the content is too long for the service instance.
 *
 * @param content The post's content.
 */
void postUpdate(String content);
Example
social.postUpdate("I love using CloudRail!!");

Post Image

Declaration
/**
 * Creates a new post/update to the currently logged in user's wall/stream/etc posting an
 * image and a message.
 * Throws an exception if the message is too long for the service instance.
 *
 * @param message The message that shall be posted together with the image.
 * @param image Stream containing the image content.
 */
void postImage(String message, InputStream image);
Example
InputStream stream = getClass().getResourceAsStream("nice_pic.jpg");
social.postImage("I love using CloudRail!!", stream);

Post Video

Declaration
/**
 * Creates a new post/update to the currently logged in user's wall/stream/etc posting a
 * video and a message.
 * Throws an exception if the message is too long for the service instance.
 *
 * @param message The message that shall be posted together with the video.
 * @param video Stream containing the video content.
 * @param size The size of the video in bytes.
 * @param mimeType The mime type of the video, for instance video/mp4.
 */
void postVideo(String message, InputStream video, long size, String mimeType);
Example
InputStream stream = getClass().getResourceAsStream("nice_vid.mp4");
social.postVideo("I love using CloudRail!!", stream, 3242456, "video/mp4");

Explicit Login

Declaration
/**
* Optional! Explicitly triggers user authentication.
* Allows better control over the authentication process.
* Optional because all methods that require prior authentication will
* trigger it automatically, unless this method has been called before.
*/
void login();
Example
social.login();

Explicit Logout

Declaration
/**
* Optional! Revokes the current authentication.
*/
void logout();
Example
social.logout();

Save As String

Declaration
/**
* A method to retrieve the data from a service that is intended for
* persistent storage.
*
* @return The data of the service that should be stored persistently,
* e.g. access credentials.
*/
String saveAsString();
Example
// Assume social and social2 are both instances of the same service
// social already has a logged in user and social2 is freshly created
String data = social.saveAsString();
social2.loadAsString(data);
// Now social2 has the same user logged in as social

Load As String

Declaration
/**
* Loads/restores data saved by saveAsString() into the service.
*
* @param savedData The persistent data that was stored.
*/
void loadAsString(String savedData);
Example
// Assume social and social2 are both instances of the same service
// social already has a logged in user and social2 is freshly created
String data = social.saveAsString();
social2.loadAsString(data);
// Now social2 has the same user logged in as social

Payment

Introduction

Payment is a common interface for services that allow you to collect payments from credit cards. It serves three main purposes: perform single charges, refund previously made charges and manage subscriptions. In order to properly test your integration, all services do provide some sort of testing environment and/or test values.

Implementing services

Function Overview

Functions

Create Charge

Declaration
/**
 * Charges a credit card and returns a charge resource.
 *
 * @param amount    A positive integer in the smallest currency unit (e.g. cents)
 *                  representing how much to charge the credit card.
 * @param currency  A three-letter ISO code for currency.
 * @param source    The credit card to be charged.
 *
 * @return  A charge resource representing the newly created payment.
 *
 * @throws IllegalArgumentException Is thrown if any of the parameters is null, amount is
 *      less than 0 or currency is not a valid three-letter currency code.
 * @throws AuthenticationException Is thrown if the provided credentials are invalid.
 * @throws HttpException Is thrown if the communication with a services fails.
 *      More detail is provided in the error message.
 */
Charge createCharge(Long amount, String currency, CreditCard source);

public class CreditCard {
    // Customer data
    private String firstName;
    private String lastName;
    private Address address;

    private String number;

    // Card validation code
    private String cvc;

    // Values between 1 and 12
    private Long expire_month;

    // Four digit expiration date
    private Long expire_year;

    // Can have the following values: visa, mastercard, discover, amex
    private String type;
}

public class Address {
    //2-letter ISO country code
    private String country;

    //City/Suburb/Town/Village
    private String city;
    private String state;

    //(Street address/PO Box/Company name)
    private String line1;

    //(Apartment/Suite/Unit/Building)
    private String line2;
    private String postalCode;
}

public class Charge {
    private String id;
    private Long amount;

    //3-letter ISO code
    private String currency;

    //The credit card info of the charge
    private CreditCard source;

    //The timestamp of when the charge was created
    private Long created;

    // Can have the following values: pending, succeeded or failed.
    private String status;

    // Indicates if the payment has been refunded.
    private boolean refunded;
}
Example
CreditCard source = new CreditCard(
    null,
    6L,
    2021L,
    "xxxxxxxxxxxxxxxx",
    "visa",
    "[FirstName]",
    "[LastName]",
    null
);

Charge charge = payment.createCharge(500L, "USD", source);
System.out.println("Charge: " + charge.toString());

Get Charge

Declaration
/**
 * Returns information about an existing charge. Mostly used to get an update
 * on the status of the charge.
 *
 * @param id The ID of the charge.
 *
 * @return A charge resource for the provided ID.
 *
 * @throws IllegalArgumentException Is thrown if id is null.
 * @throws NotFoundException Is thrown if there is now charge with that ID.
 * @throws AuthenticationException Is thrown if the provided credentials are invalid.
 * @throws HttpException Is thrown if the communication with a services fails.
 *      More detail is provided in the error message.
 */
Charge getCharge(String id);

public class Charge {
    private String id;
    private Long amount;

    //3-letter ISO code
    private String currency;

    //The credit card info of the charge
    private CreditCard source;

    //The timestamp of when the charge was created
    private Long created;

    // Can have the following values: pending, succeeded or failed.
    private String status;

    // Indicates if the payment has been refunded.
    private boolean refunded;
}

public class CreditCard {
    // Customer data
    private String firstName;
    private String lastName;
    private Address address;

    private String number;

    // Card validation code
    private String cvc;

    // Values between 1 and 12
    private Long expire_month;

    // Four digit expiration date
    private Long expire_year;

    // Can have the following values: visa, mastercard, discover, amex
    private String type;
}

public class Address {
    //2-letter ISO country code
    private String country;

    //City/Suburb/Town/Village
    private String city;
    private String state;

    //(Street address/PO Box/Company name)
    private String line1;

    //(Apartment/Suite/Unit/Building)
    private String line2;
    private String postalCode;
}
Example
Charge charge = payment.getCharge("[ChargeID]");
System.out.println("Charge: " + charge.toString());

List Charges

Declaration
/**
 * Receive a list of charges within a specified timeframe.
 *
 * @param from Timestamp representing the start date for the list.
 * @param to Timestamp representing the end date for the list.
 * @param creditCard    Optionally the credit card information so it can be
 *                      listed all the charges of this specific credit card.
 *
 * @return List of charge resources.
 *
 * @throws IllegalArgumentException Is thrown if from or to is null, from or to is less than 0, from
 *      is greater than to or to is greater than the current date.
 * @throws AuthenticationException Is thrown if the provided credentials are invalid.
 * @throws HttpException Is thrown if the communication with a services fails.
 *      More detail is provided in the error message.
 */
List<Charge> listCharges(Long from, Long to, CreditCard creditCard);

public class Charge {
    private String id;
    private Long amount;

    //3-letter ISO code
    private String currency;

    //The credit card info of the charge
    private CreditCard source;

    //The timestamp of when the charge was created
    private Long created;

    // Can have the following values: pending, succeeded or failed.
    private String status;

    // Indicates if the payment has been refunded.
    private boolean refunded;
}

public class CreditCard {
    // Customer data
    private String firstName;
    private String lastName;
    private Address address;

    private String number;

    // Card validation code
    private String cvc;

    // Values between 1 and 12
    private Long expire_month;

    // Four digit expiration date
    private Long expire_year;

    // Can have the following values: visa, mastercard, discover, amex
    private String type;
}

public class Address {
    //2-letter ISO country code
    private String country;

    //City/Suburb/Town/Village
    private String city;
    private String state;

    //(Street address/PO Box/Company name)
    private String line1;

    //(Apartment/Suite/Unit/Building)
    private String line2;
    private String postalCode;
}
Example
long current = new Date().getTime();
long aWeekAgo = current - 604800000;
List<Charge> charges = payment.listCharges(aWeekAgo, current, null);
System.out.println("Charges: " + charges.toString());

Completely Refund Charge

Declaration
/**
 * Refund a previously made charge.
 *
 * @param id The ID of the charge to be refunded.
 *
 * @return A refund resource.
 *
 * @throws IllegalArgumentException Is thrown if id is null.
 * @throws NotFoundException Is thrown if there is now charge with that ID.
 * @throws AuthenticationException Is thrown if the provided credentials are invalid.
 * @throws HttpException Is thrown if the communication with a services fails.
 *      More detail is provided in the error message.
 */
Refund refundCharge(String id);

public class Refund {
    private String id;
    private long amount;

    //Created date as a timestamp
    private long created;

    //3-letter ISO code
    private String currency;

    // Reference to the Charge that was refunded.
    private String chargeID;

    // Can have the following values: pending, succeeded or failed.
    private String state;
}
Example
Refund refund = payment.refundCharge("[ChargeID]");
System.out.println("Refund: " + refund.toString());

Partially Refund Charge

Declaration
/**
 * Refund a specified amount from a previously made charge.
 *
 * @param id The ID of the charge to be refunded.
 * @param amount The amount that shall be refunded.
 *
 * @return A refund resource.
 *
 * @throws IllegalArgumentException Is thrown if any of the parameters is null or lower/equals than 0.
 * @throws NotFoundException Is thrown if there is now charge with that ID.
 * @throws AuthenticationException Is thrown if the provided credentials are invalid.
 * @throws HttpException Is thrown if the communication with a services fails.
 *      More detail is provided in the error message.
 */
Refund partiallyRefundCharge(String id, Long amount);

public class Refund {
    private String id;
    private long amount;

    //Created date as a timestamp
    private long created;

    //3-letter ISO code
    private String currency;

    // Reference to the Charge that was refunded.
    private String chargeID;

    // Can have the following values: pending, succeeded or failed.
    private String state;
}
Example
Refund refund = payment.partiallyRefundCharge("[ChargeID]", 100L);
System.out.println("Refund: " + refund.toString());

Get Refund

Declaration
/**
 * Returns information about an existing refund. Mostly used to get an update
 * on the status of the refund.
 *
 * @param id The ID of the refund.
 *
 * @return A refund resource for the provided ID.
 *
 * @throws IllegalArgumentException Is thrown if id is null.
 * @throws NotFoundException Is thrown if there is now refund with that ID.
 * @throws AuthenticationException Is thrown if the provided credentials are invalid.
 * @throws HttpException Is thrown if the communication with a services fails.
 *      More detail is provided in the error message.
 */
Refund getRefund(String id);

public class Refund {
    private String id;
    private long amount;

    //Created date as a timestamp
    private long created;

    //3-letter ISO code
    private String currency;

    // Reference to the Charge that was refunded.
    private String chargeID;

    // Can have the following values: pending, succeeded or failed.
    private String state;
}
Example
Refund refund = payment.getRefund("[ChargeID]");
System.out.println("Refund: " + refund.toString());

Get Refunds for Charge

Declaration
/**
 * Returns information about the refunds for a specific charge.
 *
 * @param id The ID of the charge.
 *
 * @return A refund resource for the provided charge.
 *
 * @throws IllegalArgumentException Is thrown if id is null.
 * @throws NotFoundException Is thrown if there is now charge with that ID or the charge has not
 *      been refunded.
 * @throws AuthenticationException Is thrown if the provided credentials are invalid.
 * @throws HttpException Is thrown if the communication with a services fails.
 *      More detail is provided in the error message.
 */
List<Refund> getRefundsForCharge(String id);

public class Refund {
    private String id;
    private long amount;

    //Created date as timestamp
    private long created;

    //3-letter ISO code
    private String currency;

    // Reference to the Charge that was refunded.
    private String chargeID;

    // Can have the following values: pending, succeeded or failed.
    private String state;
}
Example
List<Refund> refunds = payment.getRefundsForCharge("[ChargeID]");
System.out.println("Refunds: " + refunds.toString());

Create Subscription Plan

Declaration
/**
 * Creates a subscription plan which is required to use subscription based payments.
 * The result of this method can be used together with 'createSubscription' in
 * order to subscribe someone to your subscription plan.
 *
 * @param name The name for the subscription plan.
 * @param amount The amount that is charged on a regular basis. A positive integer
 *      in the smallest currency unit (e.g. cents).
 * @param currency A three-letter ISO code for currency.
 * @param description A description for this subscription plan.
 * @param interval Specifies the billing frequency together with interval_count.
 *      Allowed values are: day, week, month or year.
 * @param interval_count Specifies the billing frequency together with interval.
 *      For example: interval_count = 2 and interval = "week" -> Billed every
 *      two weeks.
 *
 * @return Returns the newly created subscription plan resource.
 *
 * @throws IllegalArgumentException Is thrown if any of the parameters is null
 *      or lower/equal than 0, currency is not a three-letter
 *      currency code, interval is not one of the allowed values or amount is
 *      less/equal than 0.
 * @throws AuthenticationException Is thrown if the provided credentials are invalid.
 * @throws HttpException Is thrown if the communication with a services fails.
 *      More detail is provided in the error message.
 */
SubscriptionPlan createSubscriptionPlan(
    String name,
    Long amount,
    String currency,
    String description,
    String interval,
    Long interval_count
);

public class SubscriptionPlan {
    private String id;
    private String name;
    private String description;

    //Created date as a timestamp
    private long created;
    private long amount;

    //3-letter ISO code
    private String currency;

    // Can have the following values: day, week, month or year.
    private String interval;

    //Indicates how often the payment should be made. For example if interval = month and interval_count = 2, then the payment should be made twice in a month.
    private long interval_count;
}
Example
SubscriptionPlan plan = payment.createSubscriptionPlan(
    "My subscription plan",
    500L,
    "USD",
    "Awesome subscription plan.",
    "week",
    2L
);

System.out.println("Subscription Plan: " + plan.toString());

List Subscription Plans

Declaration
/**
 * Returns a list of all existing subscription plans.
 *
 * @return List of subscription plans.
 *
 * @throws AuthenticationException Is thrown if the provided credentials are invalid.
 * @throws HttpException Is thrown if the communication with a services fails.
 *      More detail is provided in the error message.
 */
List<SubscriptionPlan> listSubscriptionPlans();

public class SubscriptionPlan {
    private String id;
    private String name;
    private String description;

    //Created date as a timestamp
    private long created;
    private long amount;

    //3-letter ISO code
    private String currency;

    // Can have the following values: day, week, month or year.
    private String interval;

    //Indicates how often the payment should be made. For example if interval = month and interval_count = 2, then the payment should be made twice in a month.
    private long interval_count;
}
Example
List<SubscriptionPlan> plans = payment.listSubscriptionPlans();
System.out.println("Subscription Plans: " + plans.toString());

Create Subscription

Declaration
/**
 * Subscribes a new customer to an existing subscription plan.
 *
 * @param planID The ID of the subscription plan.
 * @param name A name for the subscription.
 * @param description A description for the subscription.
 * @param creditCard The customer that shall be subscribed.
 * @return The newly created subscription resource.
 * @throws IllegalArgumentException Is thrown if planID, name, description or
 *      payer is null.
 * @throws NotFoundException Is thrown if there is no subscription plan with
 *      the passed ID.
 * @throws AuthenticationException Is thrown if the provided credentials are invalid.
 * @throws HttpException Is thrown if the communication with a services fails.
 *      More detail is provided in the error message.
 */
Subscription createSubscription(
    String planID,
    String name,
    String description,
    CreditCard creditCard
);

public class CreditCard {
    // Customer data
    private String firstName;
    private String lastName;
    private Address address;

    private String number;

    // Card validation code
    private String cvc;

    // Values between 1 and 12
    private Long expire_month;

    // Four digit expiration date
    private Long expire_year;

    // Can have the following values: visa, mastercard, discover, amex
    private String type;
}

public class Address {
    //2-letter ISO country code
    private String country;

    //City/Suburb/Town/Village
    private String city;
    private String state;

    //(Street address/PO Box/Company name)
    private String line1;

    //(Apartment/Suite/Unit/Building)
    private String line2;
    private String postalCode;
}

public class Subscription {
    private String id;

    //The created date as a timestamp
    private Long created;
    private String name;
    private String description;

    //The plan id where the subscription belongs to
    private String subscriptionPlanID;

    //The date when did the last charge been made as a timestamp
    private Long lastCharge;

    //The date when the next will be made as a timestamp
    private Long nextCharge;
    private CreditCard creditCard;

    // Can have the following values: active or canceled.
    private String state;
}
Example
CreditCard source = new CreditCard(
    null,
    6L,
    2021L,
    "xxxxxxxxxxxxxxxx",
    "visa",
    "[FirstName]",
    "[LastName]",
    null
);

Subscription subscription = payment.createSubscription("[PlanID]", "My Subscription", "My Description", source);
System.out.println("Subscription: " + subscription.toString());

Cancel Subscription

Declaration
/**
 * Cancel an active subscription.
 *
 * @param id ID of the subscription that should be canceled.
 *
 * @throws IllegalArgumentException Is thrown if id is null.
 * @throws NotFoundException Is thrown if there is no subscription with the
 *      provided ID.
 * @throws AuthenticationException Is thrown if the provided credentials are invalid.
 * @throws HttpException Is thrown if the communication with a services fails.
 *      More detail is provided in the error message.
 */
void cancelSubscription(String id);
Example
payment.cancelSubscription("[SubscriptionID]");

SMS

Introduction

This is a common interface for Services that provide the possibility to programmatically send SMS, e.g. for signup confirmations.

Implementing services

Function Overview

Functions

Send SMS

Declaration
/**
 * Sends an SMS message, used like sendSMS("CloudRail", "+4912345678", "Hello from CloudRail").
 * Throws if an error occurs.
 *
 * @param fromName A alphanumeric sender id to identify/brand the sender. Only works in some countries.
 * @param toNumber The recipients phone number in E.164 format, e.g. +4912345678.
 * @param content   The message content. Limited to 1600 characters,
 *                  messages > 160 characters are sent and charged as multiple messages.
 */
void sendSMS(
    String fromName,
    String toNumber,
    String content
);
Example
sms.sendSMS("CloudRail", "+491234567890", "Hello from CloudRail");

Email

Introduction

This is a common interface for Services that provide the possibility to programmatically send Emails, e.g. for signup confirmations.

Implementing services

Function Overview

Functions

Send Email

Declaration
/**
 * Sends an email. Throws if an error occurs.
 *
 * @param fromAddress Mandatory. The sender email address. Must normally be registered with the corresponding service.
 * @param fromName Mandatory. The from name to be displayed to the recipient(s).
 * @param toAddresses Mandatory. A list of recipient email addresses.
 * @param subject Mandatory. The email's subject line.
 * @param textBody The email's body plain text part. Either this and/or the htmlBody must be specified.
 * @param htmlBody The email's body HTML part. Either this and/or the textBody must be specified.
 * @param ccAddresses Optional. A list of CC recipient email addresses.
 * @param bccAddresses Optional. A list of BCC recipient email addresses.
 */
void sendEmail(
    String fromAddress,
    String fromName,
    List<String> toAddresses,
    String subject,
    String textBody,
    String htmlBody,
    List<String> ccAddresses,
    List<String> bccAddresses
);
Example
email.sendEmail(
    "info@cloudrail.com",
    "CloudRail",
    Arrays.asList("foo@bar.com", "bar@foo.com"),
    "Welcome", "Hello from CloudRail",
    null,
    null,
    null
);

Points of Interest

Introduction

This is a common interface for services that provide information about Points of Interest close to a given location. This location can be specified by passing latitude and longitude as well as a search radius. Furthermore, results can be limited by providing an optional search term or a list of categories.

Implementing services

Function Overview

Functions

Get Nearby POIs

Declaration
/**
 * Returns a list of POIs that are close to the passed location and filters them by certain criteria.
 *
 * @param latitude   The latitude of the target location.
 * @param longitude  The longitude of the target location.
 * @param radius     The search radius in metres.
 * @param searchTerm Optional search term that has to be matched.
 * @param categories Optional list of categories. Available categories can be found in the main documentation.
 *
 * @return A list of POIs for the target location.
 *
 * @throws IllegalArgumentException Is thrown if latitude, longitude or radius is null, latitude or
 *                                  longitude is invalid, radius is greater than 40,000 metres or
 *                                  one of the passed categories is unknown.
 * @throws AuthenticationException  Is thrown if the passed credentials are invalid or authorization
 *                                  fails for whatever reason.
 * @throws HttpException            Is thrown if the communication with a services fails.
 *                                  More detail is provided in the error message.
 */
List<POI> getNearbyPOIs(
    Double latitude,
    Double longitude,
    Long radius,
    @Nullable String searchTerm,
    @Nullable List<String> categories
);

public class POI {
    private String name;
    private String imageURL;
    private String phone;
    private List<String> categories;
    private Location location;
}

public class Location {
    private double longitude;
    private double latitude;
}
Example
List<POI> pois = poi.getNearbyPOIs(49.4557091, 8.5279138, 3000L, "Restaurant", null);
for(POI poi : pois)
    System.out.println(poi.toString());

POI Categories

Use one or many of the below category keywords with the Points of Interest interface

  • airport
  • amusement_park
  • aquarium
  • bank
  • bar
  • beauty_salon
  • art_gallery
  • bakery
  • bicycle_store
  • book_store
  • bowling_alley
  • bus_station
  • cafe
  • car_dealer
  • car_rental
  • car_wash
  • casino
  • cemetery
  • church
  • clothing_store
  • convenience_store
  • courthouse
  • dentist
  • department_store
  • doctor
  • electronics_store
  • embassy
  • finance
  • fire_station
  • florist
  • food
  • funeral_home
  • furniture_store
  • gas_station
  • grocery_or_supermarket
  • gym
  • hardware_store
  • health
  • hindu_temple
  • hospital
  • jewelry_store
  • laundry
  • lawyer
  • library
  • locksmith
  • mosque
  • movie_theater
  • museum
  • night_club
  • parks
  • parking
  • pet_store
  • pharmacy
  • physiotherapist
  • police
  • post_office
  • real_estate_agency
  • restaurant
  • rv_park
  • school
  • shoe_store
  • shopping_mall
  • spa
  • stadium
  • synagogue
  • taxi_stand
  • train_station
  • travel_agency
  • university
  • veterinary_care
  • zoo

Advanced Request

The methods above are chosen to reflect most commonly used functionalities and thus those that all services implementing an interface have in common. It follows that the APIs of the services CloudRail integrates with offer more, service-specific functionality that is missing from CloudRail. To mitigate this, the advanced request functionality was introduced. It allows a developer to specify the raw HTTP request against an API and thus access all of its functionality. To be more than just another HTTP Client, CloudRail supports the developer by taking care of authentication and error checking.

Supported services

Currently, the advanced request function is present on all services implementing the CloudStorage interface and those implementing the Profile interface. More services will follow soon.

Example

We want to list all shared folders of a Dropbox account and know through the Dropbox API documentation that this functionality is supported by Dropbox (https://www.dropbox.com/developers/documentation/http/documentation#sharing-list_folders). Yet, it is not supported by the CloudRail Dropbox service so we use advanced request. The example assumes that you are already familiar with the installation and intialization of a CloudRail service integration.

// Initialize like usual
CloudRail.setAppKey([CloudRail key]);
Dropbox dropbox = new Dropbox([Credentials etc.]);

// Specify the URL of the Dropbox API endpoint, the base URL is prepended by default
AdvancedRequestSpecification req = new AdvancedRequestSpecification("/sharing/list_folders");

// Set the HTTP request method to POST
req.setMethod("POST");

// Specify the body and let it be converted to JSON
Map<String, Object> body = new HashMap<String, Object>();
body.put("limit", 100);
req.setBodyStringifyJson(body);

// Specify the headers
Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/json");
req.setHeaders(headers);

// Execute the request, CloudRail will start the authentication flow if necessary
// and append the authorization header.
// The response is checked for errors.
AdvancedRequestResponse res = dropbox.advancedRequest(req);

// Extract the parsed response body
Map<String, Object> parsed = (Map<String, Object>) res.getBodyJsonParsed();

// Now you can work with the answer
List<Map<String, Object>> entries = (List<Map<String, Object>>) parsed.get("entries");
System.out.println("We have " + entries.size() + " shared folders");

Specification

All supported services have an advancedRequest method:

public AdvancedRequestResponse advancedRequest(AdvancedRequestSpecification specification);

The AdvancedRequestSpecification looks like this:

public class AdvancedRequestSpecification {
    /**
     * Constructs a new advanced request specification
     *
     * @param url The request's URL
     */
    public AdvancedRequestSpecification(String url);
    
    /**
     * Specify the request's method, default is GET
     *
     * @param method The HTTP method
     */
    public void setMethod(String method);
    
    /**
     * Specify the body to sent with this request providing an InputStream
     *
     * @param body The request's body
     */
    public void setBodyAsStream(InputStream body);
    
    /**
     * Specify the body to sent with this request providing a String
     *
     * @param body The request's body
     */
    public void setBodyAsString(String body);
    
    /**
     * Specify the body to sent with this request providing an object that will be converted to JSON.
     * It must use a subclass of List for JSON-Arrays and a subclass of Map for JSON-Objects
     *
     * @param body The request's body
     */
    public void setBodyStringifyJson(Object body);
    
    /**
     * Specify the body to sent with this request providing an object that will be converted to XML.
     * The object has to have the following structure:
     *
     * type XMLElement = Map{
     *      "attributes" -> Map<string, string>,
     *      "text" -> string,
     *      "name" -> string,
     *      "children" -> List<XMLElement>
     * }
     *
     * @param body The request's body
     */
    public void setBodyStringifyXml(Map<String, Object> body);
    
    /**
     * Specify the request's (additional) headers
     *
     * @param headers An object specifying headers
     */
    public void setHeaders(Map<String, String> headers);
    
    /**
     * Disable appending authorization information to the request
     */
    public void disableAuthorization();
    
    /**
     * Disable checking the request's response for errors
     */
    public void disableErrorChecking();
    
    /**
     * Disable appending the base URL
     */
    public void disableBaseUrl();
}

The AdvancedRequestResponse looks like this:

public class AdvancedRequestResponse extends SandboxObject {
    /**
     * Returns the response's body as an InputStream
     *
     * @return The response's body
     */
    public InputStream getBodyAsStream();
    
    /**
     * Returns the response's body as a String
     *
     * @return The response's body
     */
    public String getBodyAsString();
    
    /**
     * Returns the response's body as an object resulting from JSON parsing it.
     * It uses a subclass of List for JSON-Arrays and a subclass of Map for JSON-Objects
     *
     * @return The response's body
     */
    public Object getBodyJsonParsed();
    
    /**
     * Returns the response's body as an object resulting from XML parsing it.
     * The object has the following structure:
     *
     * type XMLElement = Map{
     *      "attributes" -> Map<string, string>,
     *      "text" -> string,
     *      "name" -> string,
     *      "children" -> List<XMLElement>
     * }
     *
     * @return The response's body
     */
    public Map<String, Object> getBodyXmlParsed();
    
    /**
     * Returns the response headers as a Map
     *
     * @return The response's headers
     */
    public Map<String, String> getHeaders();
    
    /**
     * Returns the response status code as an integer
     *
     * @return The response's status code
     */
    public int getStatus();
}

Limitations

The requests are facilitated by prepending a Base URL, adding authorization and doing error checking. This assumes similar behavior in those regards of all API methods. Yet sometimes, this is not the case. You might have to disable authentication and do it on your own, e.g. because insufficient scopes are requested. You might have to disable error checking or do additional checking because the defaults are wrong or not sufficient. You might have to disable prepeding the base URL because a certain API endpoint has a different one. Do read up on each service in the Services section to learn about what base URL is prepended, what authorization appending does and which errors are caught.

Redirect Receiver

This is the most involved part of integrating CloudRail SI for Java. An implementation of this interface must be provided to every service that uses OAuth1 or OAuth2 for authentication. For others it can be left null. You can find here some example implementations.

Persistence

Some services require your users to login and authorize access. The SDK takes care of this process for you and stores the credentials required for further accesses in memory, refreshing them as needed in the background. Yet, these credentials are lost when an application is restarted, so your users might see login dialogs more often than necessary. To prevent this, there are two methods available for those services that allow you to retrieve and restore this information as needed. They are:

  • String saveAsString()
  • void loadAsString(String savedState)

We recommend to use the save method to store the data in e.g. the app storage/a database etc. on shutdown and to use the load method to restore that data upon startup.

Errors

The methods can throw one of the following Exceptions:

  • IllegalArgumentException This exception can occur if the parameters you are passing to a method are invalid. For example, a parameter is set as null when it shouldn't, a path parameter is passed without starting with / etc.

  • AuthenticationException This exception is thrown when the credentials to login to a service are invalid.

  • NotFoundException If a resource is missing then a NotFoundException is thrown. For example, if you want to create a folder to a path that doesn't exist this error will occur.

  • HttpException If any other error arise as a response from the HTTP call will be thrown as a HttpException.

  • ServiceUnavailableException Thrown if the service is temporarily unavailable.

  • RuntimeException For any other reason a simple RuntimeException is thrown.

Hints

All the calls in the SDK involve network operations and are thus potentially long running. In order to not block the main thread, these must be executed in their own threads.