OIM 11g : Multi-thread approach for writing custom scheduled job
- by Saravanan V S
In this post I have shared my experience of designing and developing an OIM schedule job that uses multi threaded approach for updating data in OIM using APIs. I have used thread pool (in particular fixed thread pool) pattern in developing the OIM schedule job. The thread pooling pattern has noted advantages compared to thread per task approach. I have listed few of the advantage here
· Threads are reused
· Creation and tear-down cost of thread is reduced
· Task execution latency is reduced
· Improved performance
· Controlled and efficient management of memory and resources used by threads
More about java thread pool http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
The following diagram depicts the high-level architectural diagram of the schedule job that process input from a flat file to update OIM process form data using fixed thread pool approach
The custom scheduled job shared in this post is developed to meet following requirement
1) Need to process a CSV extract that contains identity, account identifying key and list of data to be updated on an existing OIM resource account.
2) CSV file can contain data for multiple resources configured in OIM
3) List of attribute to update and mapping between CSV column to OIM fields may vary between resources
The following are three Java class developed for this requirement (I have given only prototype of the code that explains how to use thread pools in schedule task)
CustomScheduler.java - Implementation of TaskSupport class that reads and passes the parameters configured on the schedule job to Thread Executor class.
package com.oracle.oim.scheduler;
import java.util.HashMap;
import com.oracle.oim.bo.MultiThreadDataRecon;
import oracle.iam.scheduler.vo.TaskSupport;
public class CustomScheduler extends TaskSupport {
public void execute(HashMap options) throws Exception {
/* Read Schedule Job Parameters */
String param1 = (String) options.get(“Parameter1”);
.
int noOfThread = (int) options.get(“No of Threads”);
.
String paramn = (int) options.get(“ParamterN”);
/* Provide all the required input configured on schedule job to Thread Pool Executor implementation class like 1) Name of the file, 2) Delimiter 3) Header Row Numer 4) Line Escape character 5) Config and resource map lookup 6) No the thread to create */
new MultiThreadDataRecon(all_required_parameters, noOfThreads).reconcile();
}
public HashMap getAttributes() { return null; }
public void setAttributes() { }
}
MultiThreadDataRecon.java – Helper class that reads data from input file, initialize the thread executor and builds the task queue.
package com.oracle.oim.bo;
import <required file IO classes>;
import <required java.util classes>;
import <required OIM API classes>;
import <csv reader api>;
public class MultiThreadDataRecon {
private int noOfThreads;
private ExecutorService threadExecutor = null;
public MetaDataRecon(<required params>, int noOfThreads) {
//Store parameters locally
.
.
this.noOfThread = noOfThread;
}
/**
* Initialize
*/
private void init() throws Exception {
try {
// Initialize CSV file reader API objects
// Initialize OIM API objects
/* Initialize Fixed Thread Pool Executor class if no of threads
configured is more than 1 */
if (noOfThreads > 1) {
threadExecutor = Executors.newFixedThreadPool(noOfThreads);
} else {
threadExecutor = Executors.newSingleThreadExecutor();
}
/* Initialize TaskProcess clas s which will be executing task
from the Queue */
TaskProcessor.initializeConfig(params);
} catch (***Exception e) {
// TO DO
}
}
/**
* Method to reconcile data from CSV to OIM
*/
public void reconcile() throws Exception {
try {
init();
while(<csv file has line>){
processRow(line);
}
/* Initiate thread shutdown */
threadExecutor.shutdown();
while (!threadExecutor.isTerminated()) {
// Wait for all task to complete.
}
} catch (Exception e) {
// TO DO
} finally {
try {
//Close all the file handles
} catch (IOException e) {
//TO DO
}
}
}
/**
* Method to process
*/
private void processRow(String row) {
// Create task processor instance with the row data
// Following code push the task to work queue and wait for next
available thread to execute
threadExecutor.execute(new TaskProcessor(rowData));
}
}
TaskProcessor.java – Implementation of “Runnable” interface that executes the required business logic to update data in OIM.
package com.oracle.oim.bo;
import <required APIs>
class TaskProcessor implements Runnable {
//Initialize required member variables
/**
* Constructor
*/
public TaskProcessor(<row data>) {
// Initialize and parse csv row
}
/*
* Method to initialize required object for task execution
*/
public static void initializeConfig(<params>) {
// Process param and initialize the required configs and object
}
/*
* (non-Javadoc)
*
* @see java.lang.Runnable#run()
*/
public void run() {
if (<is csv data valid>){
processData();
}
}
/**
* Process the the received CSV input
*/
private void processData() {
try{
//Find the user in OIM using the identity matching key value from CSV
// Find the account to be update from user’s account based on account identifying key on CSV
// Update the account with data from CSV
}catch(***Exception e){
//TO DO
}
}
}