Working Asynchronously with the Remote Data Adapter
As noted in Working Synchronously or Asynchronously?, Data Abstract supports both Synchronous and Asynchronous programming styles for interacting between clients and the middle-tier.
While calling methods in a synchronous fashion is quite straight-forward and easier to do but it has one crucial drawback: low UI responsiveness. There will always be an unpredictable latency between the time you call the method and the time when you receive the result. The problem is that your users expect the UI to always be responsive and reflect their actions immediately.
This is where asynchronous support comes in, instead of hanging the UI you start off your call to the remote server and then return control to the main thread so that the UI remains fully responsive. Once the remote request completes, your code gets to take control again, and you can update your UI with the new data.
RemoteDataAdapter was designed to support both synchronous and asynchronous calls. For nearly all action methods, like login
, fill
or applyChanges
, there are asynchronous variants. The asynchronous methods take advantage of Java's Callback
mechanisms.
Samples
What follows are examples of how you would use the asynchronous methods provided by RemoteDataAdapter to carry out various operations.
Login & Logout
This sample is an example of using an asynchronous operation to both login and logout of an instance of Relativity.
public void loginAsync() {
String loginString = String.format("User=%s;Password=%s;Domain=%s;Schema=%s",
"simple", "simple", "DASamples", "Simple");
System.out.printf("Logging in with %s\n", loginString);
this.dataAdapter.loginAsync(loginString, new LoginRequestTask.Callback() {
@Override
public void completed(LoginRequestTask loginRequestTask, Object arg1) {
if(loginRequestTask.isFailed()) {
System.out.println("Cannot login. Please check the user name and password. Exiting...");
return;
} else {
System.out.println("Login has been successful.");
}
}
}).execute();
}
public void logoutAsync() {
System.out.println("Attempting to Logout");
this.dataAdapter.logoutAsync(new LoginRequestTask.Callback() {
@Override
public void completed(LoginRequestTask task, Object arg1) {
if(task.isFailed()) {
System.out.println("Cannot logout");
return;
} else {
System.out.println("Logout was successful.");
}
}
}).execute();
}
Get the Schema
public void getSchemaAsync() {
this.dataAdapter.readSchemaAsync(false, new SchemaRequestTask.Callback() {
@Override
public void completed(SchemaRequestTask task, Object arg1) {
if(task.isFailed()) {
System.out.printf("Failed to get Schema: %s", task.getFailureCause());
return;
} else {
System.out.println("Schema Retrieved");
// Objects like the dataAdapter aren't available in the
// callback, so we call a method that calls
// this.dataAdapter.readSchema which will return the now
// cached Schema data.
printSchema();
}
}
}).execute();
}
Get a Single Table
This method retrieves a single table, whose name is Clients. After it has been retrieved, the printTable
method prints out if the table has been initialised; which it will only be if the data has been retrieved from the server.
public void getTable() {
this.clientsTable = new DataTable("Clients");
this.dataAdapter.fillAsync(clientsTable, new FillRequestTask.Callback() {
@Override
public void completed(FillRequestTask task, Object arg1) {
if (task.isFailed()) {
System.out.printf("Failed to retrieve table: %s", task.getFailureCause());
} else {
System.out.println("Table Retrieved");
printTable();
}
}
}).execute();
}
private void printTable() {
System.out.printf("ClientsTable Initialised? %s\n",
String.valueOf(this.clientsTable.isInitialized()));
}
Get several tables in one go
private DataTable ordersTable;
private DataTable workersTable;
public void getTables() {
this.ordersTable = new DataTable("Orders");
this.workersTable = new DataTable("Workers");
DataTable[] tables = {this.ordersTable, this.workersTable};
System.out.printf("OrdersTable Initialised? %s\n",
String.valueOf(this.ordersTable.isInitialized()));
System.out.printf("WorkersTable Initialised? %s\n",
String.valueOf(this.workersTable.isInitialized()));
this.dataAdapter.fillAsync(tables, new FillRequestTask.Callback() {
@Override
public void completed(FillRequestTask task, Object arg1) {
if (task.isFailed()) {
System.out.printf("Failed to retrieve tables: %s\n", task.getFailureCause());
} else {
System.out.println("Tables Retrieved");
printTables();
}
}
}).execute();
}
private void printTables() {
System.out.printf("OrdersTable Initialised? %s\n",
String.valueOf(this.ordersTable.isInitialized()));
System.out.printf("WorkersTable Initialised? %s\n",
String.valueOf(this.workersTable.isInitialized()));
}
Update Data
public void applyUpdates() {
this.dataAdapter.applyChangesAsync(clientsTable, new UpdateRequestTask.Callback() {
@Override
public void completed(UpdateRequestTask task, Object arg1) {
if (task.isFailed()) {
System.out.printf("Failed to update table: %s\n", task.getFailureCause());
} else {
System.out.println("Table Updated");
}
}
}).execute();
}
Call the Remote Command
public void executeRemoteCommand() {
DataParameter[] params = {new DataParameter("ClientNotes", "Updated Details")};
this.dataAdapter.executeCommandAsync("Clients_UPDATE", params,
new CommandRequestTask.Callback() {
@Override
public void completed(CommandRequestTask task, Object arg1) {
if (task.isFailed()) {
System.out.printf("Failed to execute Remote Command: %s\n", task.getFailureCause());
} else {
System.out.println("Remote Command Executed");
}
}
}).execute();
}