Threading in the Java SDK
Threads in a Java program help you achieve parallelism. By using multiple threads, you can make a Java program run faster and do multiple things simultaneously.
The Java SDK supports both single-threading and multi-threading irrespective of a single user or a multi user app.
Refer to the below code snippets that use multi-threading for a single-user and multi-user app.
Multi-threading in a Multi-user App
Multi-threading for multi-users is achieved using Initializer's static SwitchUser().
new Initializer.Builder()
.user(user)
.environment(environment)
.token(token)
.SDKConfig(config)
.switchUser()
package threading.multiuser;
import com.zoho.api.authenticator.OAuthToken;
import com.zoho.api.authenticator.Token;
import com.zoho.api.authenticator.store.DBStore;
import com.zoho.api.authenticator.store.TokenStore;
import com.zoho.api.logger.Logger;
import com.zoho.crm.api.Initializer;
import com.zoho.crm.api.RequestProxy;
import com.zoho.crm.api.SDKConfig;
import com.zoho.crm.api.UserSignature;
import com.zoho.crm.api.dc.USDataCenter;
import com.zoho.crm.api.dc.DataCenter.Environment;
import com.zoho.crm.api.exception.SDKException;
import com.zoho.crm.api.record.RecordOperations;
import com.zoho.crm.api.util.APIResponse;
public class MultiThread extends Thread
{
Environment environment;
UserSignature user;
Token token;
String moduleAPIName;
RequestProxy userProxy;
SDKConfig sdkConfig;
public MultiThread(UserSignature user, Environment environment, Token token, String moduleAPIName, SDKConfig config, RequestProxy proxy)
{
this.environment= environment;
this.user = user;
this.token = token;
this.moduleAPIName = moduleAPIName;
this.sdkConfig = config;
this.userProxy = proxy;
}
public void run()
{
try
{
new Initializer.Builder()
.user(user)
.environment(environment)
.token(token)
.SDKConfig(sdkConfig)
.requestProxy(userProxy)
.switchUser();
System.out.println(Initializer.getInitializer().getUser().getEmail());
RecordOperations cro = new RecordOperations();
@SuppressWarnings("rawtypes")
APIResponse getResponse = cro.getRecords(this.moduleAPIName, null, null);
System.out.println(getResponse.getObject());
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args) throws SDKException
{
Logger loggerInstance = new Logger.Builder()
.level(Logger.Levels.ALL)
.filePath("/Users/user_name/Documents/java-sdk-logs.log")
.build();
Environment environment = USDataCenter.PRODUCTION;
UserSignature user1 = new UserSignature("user1@zoho.com");
TokenStore tokenstore = new DBStore.Builder()
.host("hostName")
.databaseName("databaseName")
.tableName("tableName")
.userName("userName")
.password("password")
.portNumber("portNumber")
.build();
Token token1 = new OAuthToken.Builder()
.clientID("clientId1")
.clientSecret("clientSecret1")
.refreshToken("refreshToken")
.redirectURL("redirectURL")
.build();
String resourcePath = "/Users/user_name/Documents";
SDKConfig user1Config = new SDKConfig.Builder()
.autoRefreshFields(false)
.pickListValidation(true)
.build();
new Initializer.Builder()
.user(user1)
.environment(environment)
.token(token1)
.store(tokenstore)
.SDKConfig(user1Config)
.resourcePath(resourcePath)
.logger(loggerInstance)
.initialize();
MultiThread multiThread = new MultiThread(user1, environment, token1, "Students", user1Config, null);
multiThread.start();
Environment environment1 = USDataCenter.PRODUCTION;
UserSignature user2 = new UserSignature("user2@zoho.com");
Token token2 = new OAuthToken.Builder()
.clientID("clientId1")
.clientSecret("clientSecret1")
.refreshToken("refreshToken")
.redirectURL("redirectURL")
.build();
RequestProxy user2Proxy = new RequestProxy.Builder()
.host("proxyHost")
.port(80)
.user("proxyUser")
.password("password")
.userDomain("userDomain")
.build();
SDKConfig user2Config = new SDKConfig.Builder()
.autoRefreshFields(true)
.pickListValidation(false)
.build();
multiThread = new MultiThread(user2, environment1, token2, "Leads", user2Config, user2Proxy);
multiThread.start();
}
}
The program execution starts from main().
The details of "user1" are given in the variables user1, token1, environment1.
Similarly, the details of another user "user2" are given in the variables user2, token2, environment2.
For each user, an instance of MultiThread class is created.
When start() is called which in-turn invokes run(), the details of user1 are passed to the switchUser function through the MultiThread object. Therefore, this creates a thread for user1.
Similarly, When start() is invoked again, the details of user2 are passed to the switchUser function through the MultiThread object. Therefore, this creates a thread for user2.
Multi-threading in a Single user App
package threading.singleuser;
import com.zoho.api.authenticator.OAuthToken;
import com.zoho.api.authenticator.Token;
import com.zoho.api.authenticator.store.FileStore;
import com.zoho.api.authenticator.store.TokenStore;
import com.zoho.api.logger.Logger;
import com.zoho.api.logger.Logger.Levels;
import com.zoho.crm.api.Initializer;
import com.zoho.crm.api.SDKConfig;
import com.zoho.crm.api.UserSignature;
import com.zoho.crm.api.dc.USDataCenter;
import com.zoho.crm.api.dc.DataCenter.Environment;
import com.zoho.crm.api.record.RecordOperations;
import com.zoho.crm.api.util.APIResponse;
public class MultiThread extends Thread
{
String moduleAPIName;
public MultiThread(String moduleAPIName)
{
this.moduleAPIName = moduleAPIName;
}
public void run()
{
try
{
RecordOperations record = new RecordOperations();
@SuppressWarnings("rawtypes")
APIResponse getResponse = record.getRecords(this.moduleAPIName, null, null);
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args) throws SDKException
{
Logger logger = new Logger.Builder()
.level(Levels.INFO)
.filePath("/Users/user_name/Documents/java-sdk-logs.log")
.build();
Environment environment = USDataCenter.PRODUCTION;
TokenStore tokenStore = new FileStore("/Users/user_name/Documents/java-sdk-tokens.txt");
UserSignature user = new UserSignature("user1@zoho.com");
Token token = new OAuthToken.Builder()
.clientID("clientId1")
.clientSecret("clientSecret1")
.refreshToken("refreshToken")
.redirectURL("redirectURL")
.build();
SDKConfig sdkConfig = new SDKConfig.Builder()
.autoRefreshFields(false)
.pickListValidation(true)
.build();
String resourcePath = "/Users/user_name/Documents/javasdk-application";
new Initializer.Builder()
.user(user)
.environment(environment)
.token(token)
.store(tokenstore)
.SDKConfig(sdkConfig)
.resourcePath(resourcePath)
.logger(logger)
.initialize();
MultiThread mtsu = new MultiThread("Deals");
mtsu.start();
mtsu = new MultiThread("Leads");
mtsu.start();
}
}
Multi-threading in a Single-user App
- The program execution starts from Main() where the SDK is initialized with the details of user and an instance of MultiThread class is created .
- When the Start() is called which in-turn invokes the run(), the moduleAPIName is switched through the method parameter. Therefore, this creates a thread for the particular method called with the MultiThread instance.
- The MultiThread object is reinitialized with a different moduleAPIName.
SDK Sample Code
import com.zoho.api.authenticator.Token;
import com.zoho.api.authenticator.store.DBStore;
import com.zoho.api.authenticator.store.FileStore;
import com.zoho.api.authenticator.store.TokenStore;
import com.zoho.crm.api.exception.SDKException;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import com.zoho.api.authenticator.OAuthToken;
import com.zoho.crm.api.HeaderMap;
import com.zoho.crm.api.Initializer;
import com.zoho.crm.api.ParameterMap;
import com.zoho.crm.api.SDKConfig;
import com.zoho.crm.api.UserSignature;
import com.zoho.crm.api.dc.DataCenter.Environment;
import com.zoho.crm.api.dc.USDataCenter;
import com.zoho.api.logger.Logger;
import com.zoho.api.logger.Logger.Levels;
import com.zoho.crm.api.record.RecordOperations;
import com.zoho.crm.api.record.ResponseHandler;
import com.zoho.crm.api.record.ResponseWrapper;
import com.zoho.crm.api.tags.Tag;
import com.zoho.crm.api.record.RecordOperations.GetRecordsHeader;
import com.zoho.crm.api.record.RecordOperations.GetRecordsParam;
import com.zoho.crm.api.util.APIResponse;
public class Record
{
public static void main(String[] args) throws SDKException
{
/*
* Create an instance of Logger Class that takes two parameters
* level -> Level of the log messages to be logged. Can be configured by typing Levels "." and choose any level from the list displayed.
* filePath -> Absolute file path, where messages need to be logged.
*/
Logger logger = new Logger.Builder()
.level(Levels.INFO)
.filePath("/Users/user_name/Documents/java-sdk-logs.log")
.build();
//Create an UserSignature instance that takes user Email as parameter
UserSignature user = new UserSignature("abc@zoho.com");
/*
* Configure the environment
* which is of the pattern Domain.Environment
* Available Domains: USDataCenter, EUDataCenter, INDataCenter, CNDataCenter, AUDataCenter
* Available Environments: PRODUCTION, DEVELOPER, SANDBOX
*/
Environment environment = USDataCenter.PRODUCTION;
/*
* Create a Token instance
* clientID -> OAuth client id.
* clientSecret -> OAuth client secret.
* refreshToken -> refresh token.
* redirectURL -> OAuth redirect URL.
*/
Token token = new OAuthToken.Builder()
.clientID("clientId1")
.clientSecret("clientSecret1")
.refreshToken("refreshToken")
.redirectURL("redirectURL")
.build();
/*
* Create an instance of TokenStore.
* host -> DataBase host name. Default "jdbc:mysql://localhost"
* databaseName -> DataBase name. Default "zohooauth"
* userName -> DataBase user name. Default "root"
* tableName -> DataBase table name. Default "oauthtoken"
* password -> DataBase password. Default ""
* portNumber -> DataBase port number. Default "3306"
*/
// TokenStore tokenstore = new DBStore.Builder().build();
TokenStore tokenstore = new DBStore.Builder()
.host("hostName")
.databaseName("databaseName")
.tableName("tableName")
.userName("userName")
.password("password")
.portNumber("portNumber")
.build();
// TokenStore tokenstore = new FileStore("absolute_file_path");
/*
* autoRefreshFields (default value is false)
* true - all the modules' fields will be auto-refreshed in the background, every hour.
* false - the fields will not be auto-refreshed in the background. The user can manually delete the file(s) or refresh the fields using methods from ModuleFieldsHandler
*
* pickListValidation (default value is true)
* A boolean field that validates user input for a pick list field and allows or disallows the addition of a new value to the list.
* true - the SDK validates the input. If the value does not exist in the pick list, the SDK throws an error.
* false - the SDK does not validate the input and makes the API request with the user’s input to the pick list
*/
SDKConfig config = new SDKConfig.Builder()
.autoRefreshFields(true)
.pickListValidation(false)
.build();
String resourcePath = "/Users/user_name/Documents/javasdk-application";
/*
* Set the following in InitializeBuilder
* user -> UserSignature instance
* environment -> Environment instance
* token -> Token instance
* store -> TokenStore instance
* SDKConfig -> SDKConfig instance
* resourcePath -> resourcePath - A String
* logger -> Log instance (optional)
* requestProxy -> RequestProxy instance (optional)
*/
new Initializer.Builder()
.user(user)
.environment(environment)
.token(token)
.store(tokenstore)
.SDKConfig(config)
.resourcePath(resourcePath)
.logger(logger)
.initialize();
String moduleAPIName = "Leads";
RecordOperations recordOperations = new RecordOperations();
ParameterMap paramInstance = new ParameterMap();
paramInstance.add(GetRecordsParam.APPROVED, "both");
HeaderMap headerInstance = new HeaderMap();
OffsetDateTime enddatetime = OffsetDateTime.of(2020, 05, 20, 10, 00, 01, 00, ZoneOffset.of("+05:30"));
headerInstance.add(GetRecordsHeader.IF_MODIFIED_SINCE, enddatetime);
//Call getRecords method
APIResponseresponse = recordOperations.getRecords(moduleAPIName, paramInstance, headerInstance);
if(response != null)
{
//Get the status code from response
System.out.println("Status Code: " + response.getStatusCode());
if(Arrays.asList(204,304).contains(response.getStatusCode()))
{
System.out.println(response.getStatusCode() == 204? "No Content" : "Not Modified");
return;
}
//Check if expected response is received
if(response.isExpected())
{
//Get the object from response
ResponseHandler responseHandler = response.getObject();
if(responseHandler instanceof ResponseWrapper)
{
//Get the received ResponseWrapper instance
ResponseWrapper responseWrapper = (ResponseWrapper) responseHandler;
//Get the obtained Record instances
List records = responseWrapper.getData();
for(com.zoho.crm.api.record.Record record : records)
{
//Get the ID of each Record
System.out.println("Record ID: " + record.getId());
//Get the createdBy User instance of each Record
com.zoho.crm.api.users.User createdBy = record.getCreatedBy();
//Check if createdBy is not null
if(createdBy != null)
{
//Get the ID of the createdBy User
System.out.println("Record Created By User-ID: " + createdBy.getId());
//Get the name of the createdBy User
System.out.println("Record Created By User-Name: " + createdBy.getName());
//Get the Email of the createdBy User
System.out.println("Record Created By User-Email: " + createdBy.getEmail());
}
//Get the CreatedTime of each Record
System.out.println("Record CreatedTime: " + record.getCreatedTime());
//Get the modifiedBy User instance of each Record
com.zoho.crm.api.users.User modifiedBy = record.getModifiedBy();
//Check if modifiedBy is not null
if(modifiedBy != null)
{
//Get the ID of the modifiedBy User
System.out.println("Record Modified By User-ID: " + modifiedBy.getId());
//Get the name of the modifiedBy User
System.out.println("Record Modified By User-Name: " + modifiedBy.getName());
//Get the Email of the modifiedBy User
System.out.println("Record Modified By User-Email: " + modifiedBy.getEmail());
}
//Get the ModifiedTime of each Record
System.out.println("Record ModifiedTime: " + record.getModifiedTime());
//Get the list of Tag instance each Record
List tags = record.getTag();
//Check if tags is not null
if(tags != null)
{
for(Tag tag : tags)
{
//Get the Name of each Tag
System.out.println("Record Tag Name: " + tag.getName());
//Get the Id of each Tag
System.out.println("Record Tag ID: " + tag.getId());
}
}
//To get particular field value
System.out.println("Record Field Value: " + record.getKeyValue("Last_Name"));// FieldApiName
System.out.println("Record KeyValues: " );
//Get the KeyValue map
for(Map.Entry entry : record.getKeyValues().entrySet())
{
String keyName = entry.getKey();
Object value = entry.getValue();
if(value != null)
{
System.out.println("Field APIName : " + keyName + "\tValue : " + value.toString());
}
}
}
}
}
}
}
}
,>