Oct 3, 2013

I had developed this utility on swing back in 2009. This utility can be used to schedule shutdown, lock, sleep, hibernate, reboot and log off operations in windows.

Earlier this utility was based on external dependencies and due to this dependency the utility was not working anymore . Now I have created two versions of the utility Shutdown-basic* and Shutdown jar. The difference lies in the component used to select the date and time for scheduling the operation.

Shutdown.jar:  This utility utilizes a advanced swing component to select date and time.  As this swing component is for trial version only, using it after the trial period might give you exception during launch, but the functionality will still work.

Shutdownbasic.jar:  This is a standalone utility which does not use any proprietary swing component, so it will work without issues.

Using the application:-

  • The jar is runnable, so just launch the application by opening command prompt at the application folder and invoking "java -jar shutdown.jar" (without the quotes) or “java –jar shutdownbasic.jar” command or you can set it to open with java by default.
  • Select the time and date for the scheduling the operation.
  • Select the operation from the drop down box that you want to execute and click on the submit button.
  • One can always abort the current operation in between by clicking on the abort button.
  • The label at the bottom will display the time left for the execution of the operation.

 

Download the application from the link below:-








Following are the snapshots of the application:-


shutdown utility shutdown utility2

shutdown utility3 shutdown utility4



Note:- Its always recommended to create a shortcut for running jar files. So just create a shortcut and in the target prefix the command 'javaw -jar' and save the shortcut.

Posted on Thursday, October 03, 2013 by Unknown

Aug 13, 2013

To determine code quality of an application,lot of tools are available such as PMD, FindBugs,etc. During the product development life-cycle there are various phases such as unit testing, code coverage analysis, performance testing ,and code quality analysis. SonarQube is one such open source tool that aggregates the aforementioned metrics into a single dashboard through which one can see, manage and iteratively improve upon such aspects. SonarQube has a plug-in based architecture and you can use this tool to analyze different languages within the same project and can maintain a central repository to track changes, assign and resolve issues.

In this post i will share an example of code analysis done by SonarQube for an ADF project, I have configured MySQL database as a repository for the SonarQube application. I have also extended the existing rule sets by adding a XPATH rule; This rule is based on PMD xpath template that flags the use of getRowSetIterator() method. The steps for running the analysis are mentioned below.
  1. Assuming sonar-runner in your classpath and SONAR_RUNNER_HOME  is configured, create sonar-project.properties in the application directory of your application as shown below :-
    # required metadata
    sonar.projectKey=com.blogspot.ramannanda.MasterDetail
    sonar.projectName=ADF Project
    sonar.projectVersion=1.0
     
    # optional description
    sonar.projectDescription=Master Detail Example
    
    #project modules
    sonar.modules=Model,ViewController
    
    # The value of the property must be the key of the language.
    sonar.language=java
    
    # Encoding of the source code
    sonar.sourceEncoding=UTF-8



  2. Create module specific sonar-project.properties files as shown below
    #For model project
    # required metadata
    sonar.projectName=Model
    sonar.projectVersion=1.0
     
    # path to source directories (required)
    sonar.sources=src
     
    # optional description
    sonar.projectDescription=Model for Master Detail
    
    #path to binaries
    sonar.binaries=classes 

    For viewcontroller project the configuration is similar as shown below

    # required metadata
    sonar.projectName=ViewController
    sonar.projectVersion=1.0
     
    # path to source directories (required)
    sonar.sources=src
    
    #optional description
    sonar.projectDescription=ViewController project for 
    
    #path to binaries
    sonar.binaries=classes 



  3. Just type the sonar-runner command in the application directory and analysis will be performed, after which you can open the application and view the analysis for the project


Extending the rule sets:-


Now i will provide an example of how to extend  the application with a custom XPATH rule.



  1. Go to Quality Profile menu and select a java profile


  2. Search for xpath rule; there might be two disabled rules. I have chosen the PMD xpath template rule, as it is currently the supported rule for java and expressions can easily be checked using PMDDesigner utility. The screenshot is shown below.SonarQube _Rule


  3. The xpath expression for the rule is shown in the below snippet.
    //PrimaryExpression/PrimaryPrefix/Name[contains(@Image,'getRowSetIterator')]



  4. Activate the rule and run the analysis with sonar-runner utility; After running the analysis we can see the rule violations for the project.


sonarqube_custom_pmd_rule





As can be seen from the screen-shot, we also have the option to assign the issue to an individual, browse the source code, see how long a issue has been opened, etc. So all in all this tool is a good place to maintain the metrics about the project. Probably, in future, people can extend the functionality further for ADF application by creating more rule sets applicable to ADF application.





References:-


http://www.sonarqube.org/


http://pmd.sourceforge.net/pmd-5.0.5/xpathruletutorial.html


Some Screens:


SonarQube - ADFProject


SonarQube_treemap

Posted on Tuesday, August 13, 2013 by Unknown

Apr 22, 2013

Developers while creating the applications often ignore guidelines of closing result sets which is the most common cause of memory leaks. In ADF applications it is the RowSetIterators that need to be closed . This scenario can easily be simulated under load testing using jmeter and turning on memory sampling in JVisualVM.  In this post i will share an example of a one page application in which there is a depiction of master detail relationship b/w a department and its employees. There is a disabled af:inputtext on the fragment that is bound to a backing bean and its getter method has code for iterating the employee table and calculating the total employee salary. Initially i have created a secondary row set iterator and left it open just to examine the memory leaks under load that occur due to this open reference. The code in the backing bean is shown below.

    public Number getSum() {
DCBindingContainer bc=(DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
EmpVOImpl empVoImpl=(EmpVOImpl)bc.findIteratorBinding("EmpVO1Iterator").getViewObject();
Number totalAmount=new Number(0);
RowSetIterator it= empVoImpl.createRowSetIterator(null);
while(it.hasNext()){
EmpVORowImpl row=(EmpVORowImpl)it.next();
if(row.getSal()!=null){
totalAmount=row.getSal().add(totalAmount);
}
}
it.closeRowSetIterator();
this.sum=totalAmount;
return sum;
}


So to identify that you have open iterator issue, open the JVisualVM’s sampler tab and turn on memory sampling, when you do so you would see many instances of different types of classes but to identify open iterator issue you need to focus on ViewRowSetIteratorImpl instances and then to your project specific VOImpl classes through which you obtained the iterator in the first place. When ever you create a new RowSetIterator you are returned a ViewRowSetIteratorImpl class instance. As is obvious you would expect the number of instances to increase as you open the RowSetIterator instances and do not close them. Now when i ran the application under simulated load with JMeter with open iterator reference i could see the instances for ViewRowSetIteratorImpl class increase in number very quickly. So then i took a heap dump with JVisualVM and then clicked on the ViewRowSetIteratorImpl class in classes tab to open the instance view tab, then upon selecting an instance and querying for the nearest GC root (in the reference section) i could see that EmpVOImpl was holding a reference to the ViewRowSetIteratorImpl instance. You can also use OQL support in JVisualVM to find out the references which are keeping the object alive.



select  heap.livepaths(u,false) from oracle.jbo.server.ViewRowSetImpl u


adfgcroot



livepaths



After opening the EmpVOImpl instance by clicking on the node, I expanded the mviewrowset (it is a variable which holds ViewRowSetImpl  instance) and then further expanding its mViews property i could see a number of ViewRowSetIteratorImpl instances as shown below.



empvoimplholdingviewrowsetiteratorimpl



So to resolve this issue all i had to do was to close the open iterator by calling the closeRowSetIterator method on the RowSetIterator instance.



There are other alternatives also for identifying the problem in your source code by turning on profiling in JVisualVM but profiling on a production system is not recommended way of even approaching the issue.



The comparison b/w the application with open iterators and closed iterators is shown below.



 



adfmemoryleak nomemoryleakiteratorclose



In this application JMeter was used to simulate the load with loop controller configured to select different master rows so that upon selection change and partial refresh the getter method for the inputtext in backing bean was called again and again to increase the iterator instances.



jmeterconf



The application and jmx file can be downloaded from below links




  1. JMeter test plan


  2. Application

Posted on Monday, April 22, 2013 by Unknown

Apr 19, 2013

A user on OTN forum was trying to extend the AdfcExceptionHandler in which he was trying to do redirect to an error page and facing Response Already Committed exception. On examining the scenario i could see that the phase in which the exception handler was being called was RENDER_RESPONSE and by this time it is too late to do a redirect as part of the response has already been submitted (one can check this by using response.iscommitted() method). So redirects/forwards should never be issued from the AdfcExceptionHandler in a conventional way.

The question also arises why someone needs to extend the AdfcExceptionHandler  in the first place, but, we need to do this as default exception handling will not handle exceptions that occur during render response phase for example: let’s say that during the application execution the connectivity to the DB goes down, the exceptions raised then will not be handled by the default exception handling mechanism.

So we cannot use conventional redirects but we have to do redirects somehow, the solution then is to use javascript redirect from the exception handler. The code for the exception handler is shown below.

package com.blogspot.ramannanda.view.handlers;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseId;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import oracle.adf.view.rich.context.ExceptionHandler;
import oracle.adfinternal.controller.application.AdfcExceptionHandler;
import oracle.jbo.DMLException;
import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
import org.apache.myfaces.trinidad.util.Service;


public class MyAppUIErrorHandler extends AdfcExceptionHandler {
public MyAppUIErrorHandler() {
super();
}


@Override
public void handleException(FacesContext facesContext, Throwable throwable,
PhaseId phaseId) throws Throwable {
ExternalContext ctx =
FacesContext.getCurrentInstance().getExternalContext();
HttpServletRequest request = (HttpServletRequest)ctx.getRequest();
if (phaseId.getOrdinal() == PhaseId.RENDER_RESPONSE.getOrdinal()) {
//handle null pointer or sqlexception or runtime DMLException that might occur
if (throwable instanceof DMLException ||
throwable instanceof SQLException ||
throwable instanceof NullPointerException) {
String contextPath = request.getContextPath();
FacesContext context = FacesContext.getCurrentInstance();
StringBuffer script = new StringBuffer();
//set the window.location.href property this causes the redirect.
script.append("window.location.href= '").append(contextPath).append("/error.html';");
ExtendedRenderKitService erks =
Service.getRenderKitService(context,
ExtendedRenderKitService.class);
erks.addScript(context, script.toString());
//encoding script is required as just adding script does not work here
erks.encodeScripts(context);
return;
} else {
super.handleException(facesContext, throwable, phaseId);
}

}


}
}


So by using this code we are doing redirect to error.html page, I am also checking for phaseId here as the handler will be called for each phase in turn and we can do the handling in render response phase.



Note: Note that i have used encodeScripts method after adding the script and this is required because this method outputs any required scripts by RenderKit which in our case tends to be the script we added. 



 



adferrorhandling

Posted on Friday, April 19, 2013 by Unknown

Apr 2, 2013

In this post i will share some scenarios that you might face with ADF Master Detail Table component. Typically those mentioned below:-

  1. Create a row in child table on creation of row in master table (uses Accessor to programmatically create a row in child )
  2. Using Cascade delete option on committed rows

The code sample is based upon scott schema and uses dept and emp tables. The dept table serves as master table and the emp table serves as child table. Also,the association relationship between the entities involved is a composition relationship.

There are a few pre-requisites for this sample to work, basically, you need to create triggers on both the tables and database sequences that will be used to populate  primary key values. The SQL script is present in the sample app.

 

1. Creating row in child table whenever a row is created in master table:-

To accomplish this i have created a method in the application module implementation class that creates a row for department programmatically and then uses the exposed accessor to create the row in child. The snippet is shown below :-

    /**
* Creates and inserts Dept and Emp Row
*/
public void createDeptAndEmpRow(){
DeptVOImpl deptVO=this.getDeptVO1();
DeptVORowImpl row=(DeptVORowImpl)deptVO.createRow();
deptVO.insertRow(row);
RowIterator iterator= row.getEmpVO();
Number deptNumber=row.getDeptno().getSequenceNumber();
NameValuePairs nvps=new NameValuePairs();
nvps.setAttribute("Deptno", deptNumber);
EmpVORowImpl empRow=(EmpVORowImpl)iterator.createAndInitRow(nvps);
iterator.insertRow(empRow);
}


Here i have used the *VOImpl and *VORowImpl class implementations. Also note  the partial triggers on employee table for “create department and employee button” and “Delete department” button which causes the employee table to refresh.



2. Using cascade delete option on committed rows:-



Default database foreign key constraints ensure that you cannot delete rows from a parent while records exist in child table, so if you issue a delete statement on master table i.e Department table you will receive a  foreign key constraint violation exception. The solution is to make the foreign key constraint deferrable which ensures that validation happens when you issue a  commit and not while you issue the delete statement. So to get this to work drop the existing constraint and recreate it as following.



ALTER TABLE emp
ADD CONSTRAINT fk_deptno
FOREIGN KEY (deptno)
REFERENCES dept (deptno)
ON DELETE CASCADE
DEFERRABLE
INITIALLY DEFERRED ;


 



Also note the “ON DELETE CASCADE” clause which will delete the records in child table whenever a row from master table is deleted.



 



The database scripts for triggers and sequences are present in the sample project which can be downloaded from here.



masterdetailexample



 associationrelationship

Posted on Tuesday, April 02, 2013 by Unknown

Mar 3, 2013

If you have a requirement to reconcile user status from target resource and also to provision the value of user status into a target account you can follow this post.
Let’s say for example in the target resource the status is marked as A for enable and  D for disable. To accomplish this using GTC connector you will need a lookup based translation.
Provisioning:
For provisioning let’s assume that the target database application table has a column USER_STATUS corresponding to the Status column in OIM, Also the target has different statuses corresponding to the statuses in OIM. To accomplish the provisioning then follow these steps:-
  1. Create a lookup definition as shown in below snapshot

    oimprovstatuslookup
  2. Now create the GTC connector and do not choose the trusted source reconciliation as this is an example of target resource reconciliation and provisioning. Now map the OIM user dataset Status column to the provisioning staging dataset’s USER_STATUS column and choose “create mapping with translation” option. The mapping should be as shown in the below screenshot.

    provstatusmapping
  3. Now when the provisioning happens the USER_STATUS will be populated as A and when you will disable the user the USER_STATUS will be set as D on the target resource.
Reconciliation:
If you also have to reconcile the target’s resource status with OIM’s resource status  and the target resource has different values for the statuses than OIM then follow the below mentioned steps:-
  1. Create a another lookup (you could also use same lookup) that maps the target’s statuses to OIM’s statuses. Since this is target resource reconciliation the statuses will be Enabled and Disabled on OIM side But,if this were trusted resource reconciliation these would have been Active and Disabled on OIM side. The screenshot below shows the lookup.

    reconcilestatuslookup
  2. Now go to reconciliation mapping of the GTC connector and in the reconciliation staging dataset add a column and name it RECONCILE_STATUS and choose “Create mapping with Translation” option and map the USER_STATUS field  to the the reconciliation lookup literal which has the mapping for translation.  Refer to the below screenshots.

    statusreconcile_trans1
    statusreconcile_trans2
  3. After the above mapping map is done map the new RECONCILE_STATUS column in Reconciliation staging dataset to the OIM_OBJECT_STATUS field in the OIM account data set.

    reconcileoimobjectstatus
This completes the mapping for the GTC connector now you can test the provisioning and  reconciliation.To test the reconciliation change the status from A TO D in the target database table and run the OIM reconciliation scheduler which in turn will generate the event and the resource will be disabled in OIM for the particular user.
The following screenshot shows how the entire mapping looks like.
gtcscreen

Posted on Sunday, March 03, 2013 by Unknown

Mar 2, 2013

I recently faced an issue that after installing and configuring IDM domain, when i tried to run the config.bat for oim server the script was crashing on my windows 7 OS. The problems faced by me are mentioned below along with the causes and solutions.
  1. Problem: Setup.exe has stopped working; Solution: Try placing the JDK in a directory that does not contain spaces and make sure that if you are using windows 7 64 bit OS the jre is also 64 bit. To specify the jre location to the config script place it in the config.bat script as mentioned in below snippet.
    %ORACLE_HOME%\oui\bin\setup.exe %ARGS% -debug -jreLoc C:\jdk1.6.0_18\jre 

    The above snippet also enables debugging which is helpful in fixing any other issues that you might face.



  2. Problem: Setup.exe crashes with FileNotFoundException, This problem was happening because of the fact that config.bat specifies an additional parameter “-oneclick” which causes the setup.exe to look for oneclick.properties; Solution: This property is not required so open the config.bat and remove this property.



  3. Problem: JVM crashes with access violation exception, This problem causes jvm to dump the process state and occurs due to compatibility issue A small snippet of process dump that shows the issue is mentioned below ; Solution: Go to the setup.exe process in oui/bin directory and under the compatibility tab for the process check  disable visual themes and desktop composition .

    #
    # A fatal error has been detected by the Java Runtime Environment:
    #
    #  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0000000077080895, pid=6968, tid=6860
    #
    # JRE version: 6.0_18-b07
    # Java VM: Java HotSpot(TM) 64-Bit Server VM (16.0-b13 mixed mode windows-amd64 )
    # Problematic frame:
    # C  [ntdll.dll+0x50895]
    #
    # If you would like to submit a bug report, please visit:
    #   http://java.sun.com/webapps/bugreport/crash.jsp

    compatsetup

Phew ! thats a lot of issues for one installer hope it saves someone else's time cause it sure didn't save mine.

Posted on Saturday, March 02, 2013 by Unknown

Jan 4, 2013

In this post i am sharing the process to make your own custom reconciliation connector. The process flow of the scheduler is shown in the below flowchart.

 

customtargetreconciliation

This flow chart is a simplified version and should serve as a simple aid. The code for the 11g scheduler is shown below, it is a pretty crude implementation and just serves as a POC it does a full target reconciliation.

public class UserDetailReconTask extends TaskSupport {
private static final ADFLogger reconLogger =
ADFLogger.createADFLogger(UserDetailReconTask.class);

public UserDetailReconTask() {
super();
}


public void execute(HashMap hashMap) {
String methodName =
Thread.currentThread().getStackTrace()[1].getMethodName();
tcITResourceInstanceOperationsIntf itRes =
Platform.getService(tcITResourceInstanceOperationsIntf.class);
reconLogger.entering(methodName, hashMap.toString());
//get it resourcename
String itResourceName = hashMap.get("ITResource").toString();
//Get resource object to reconcile
String resourceObjectName = hashMap.get("ResourceObject").toString();
//Get table name
String tableName = hashMap.get("TableName").toString();
HashMap hashmap = new HashMap();
if (reconLogger.isLoggable(Level.INFO)) {
reconLogger.info("[ " + methodName + " ] " +
"Got It Resource name " + itResourceName);
}
hashmap.put("IT Resources.Name", itResourceName);
tcResultSet rss;
tcResultSet parameters;
HashMap paramsMap = new HashMap();
try {
rss = itRes.findITResourceInstances(hashmap);
Long ll = rss.getLongValue("IT Resource.Key");

parameters = itRes.getITResourceInstanceParameters(ll);
for (int i = 0; i < parameters.getRowCount(); i++) {
parameters.goToRow(i);
String paramName =
parameters.getStringValue("IT Resources Type Parameter.Name");
if (paramName.trim().equalsIgnoreCase("DatabaseName")) {
paramsMap.put("DatabaseName",
parameters.getStringValue("IT Resource.Parameter.Value"));
} else if (paramName.trim().equalsIgnoreCase("URL")) {
paramsMap.put("URL",
parameters.getStringValue("IT Resource.Parameter.Value"));
} else if (paramName.trim().equalsIgnoreCase("UserID")) {
paramsMap.put("UserID",
parameters.getStringValue("IT Resource.Parameter.Value"));
} else if (paramName.trim().equalsIgnoreCase("Password")) {
paramsMap.put("Password",
parameters.getStringValue("IT Resource.Parameter.Value"));
} else if (paramName.trim().equalsIgnoreCase("Driver")) {
paramsMap.put("Driver",
parameters.getStringValue("IT Resource.Parameter.Value"));
}
}
} catch (tcAPIException e) {
reconLogger.severe("[ " + methodName + " ] " +
"error occured during retrieving IT Resource",
e);
throw new RuntimeException("[ " + methodName + " ] " +
"error occured during retrieving IT Resource");
} catch (tcColumnNotFoundException e) {
reconLogger.severe("[ " + methodName + " ] " +
"error occured during retrieving IT Resource column name",
e);
throw new RuntimeException("[ " + methodName + " ] " +
"error occured during retrieving IT Resource column name");
} catch (tcITResourceNotFoundException e) {
reconLogger.severe("[ " + methodName + " ] " +
"error occured during retrieving IT Resource by key",
e);
throw new RuntimeException("[ " + methodName + " ] " +
"error occured during retrieving IT Resource by key");
}
reconcileAndCreateEvents(paramsMap.get("UserID").toString(),
paramsMap.get("Password").toString(),
paramsMap.get("Driver").toString(),
paramsMap.get("URL").toString(),
resourceObjectName, tableName);

reconLogger.exiting("UserDetailReconTask", methodName);
}

public HashMap getAttributes() {
return null;
}

public void setAttributes() {
}


/**
* This method gets the data from the source table and then creates the events after
* that OIM applies the rules to check whether the user is there or not
* @param adminID Source admin user id
* @param password Source Password
* @param Driver Driver type
* @param Url jdbc url of the target database
* @param resourceObject target resource object
* @param tableName The target table to reconcile from
*/
private void reconcileAndCreateEvents(String adminID, String password,
String Driver, String Url,
String resourceObject,
String tableName) {
String methodName =
Thread.currentThread().getStackTrace()[1].getMethodName();
reconLogger.entering("UserDetailReconTask", methodName);
ResultSet rs = null;
Connection conn = null;
PreparedStatement ps = null;
try {
Class.forName(Driver);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unable to find the driver class", e);
}
try {
tcReconciliationOperationsIntf reconService =
Platform.getService(tcReconciliationOperationsIntf.class);
HashMap dataMap = new HashMap();
conn = DriverManager.getConnection(Url, adminID, password);
ps = conn.prepareStatement("Select * from "+ tableName);
rs = ps.executeQuery();
reconLogger.info("[ " + methodName + " ] " +
"Executed the query succesfully");
while (rs.next()) {
//put data in map
dataMap.put("UserLogin", rs.getString(1));
//create reconciliation event
reconLogger.info("[ " + methodName + " ] " + "Got login Id ",
rs.getString(1));
try {
//create reconciliation event
reconService.createReconciliationEvent(resourceObject,
dataMap, true);
reconLogger.info("[ " + methodName + " ] " +
"Created Recon Event", rs.getString(1));

} catch (tcObjectNotFoundException e) {
reconLogger.severe("Unable to find resource object");
throw new RuntimeException("Unable to find the driver class",
e);
} catch (tcAPIException e) {
reconLogger.severe("Unable to find resource object");
throw new RuntimeException("Unable to createevent", e);
}
}

} catch (SQLException e) {
throw new RuntimeException("Unable to get connection", e);
}
}
}


 



Here the method of relevance is reconcileAndCreateEvent which actually fetches the details from the target table name and then it is being used to populate a dataMap with reconciliation field names and value, this along with the resource object name is being used to create the reconciliation event which in turn is then processed by OIM Reconciliation engine which finds a reconciliation rule corresponding to the resource object and then applies the rule, in this case UserLogin is matched with User_Login in OIM and the account linking is performed.



The reconciliation API reference link is here.



The scheduler xml is shown below. It is named as UserDetailReconTask.xml and needs to be imported into mds using weblogicImportMetada.sh script.The  path needs to be /db/UserDetailReconTask.xml



<scheduledtasks xmlns="http://xmlns.oracle.com/oim/scheduler">
<task>
<name>UserDetailReconTask</name>
<class>com.blogspot.ramannanda.schedulers.UserDetailReconTask</class>
<description>Target Reconciliation</description>
<retry>5</retry>
<parameters>
<string-param required="true" encrypted="false" helpText="IT Resource">ITResource</string-param>
<string-param required="true" encrypted="false" helpText="Resource Object name">ResourceObject</string-param>
<string-param required="true" encrypted="false" helpText="Table Name">TableName</string-param>
</parameters>
</task>
</scheduledTasks>


The plugin xml is mentioned below



<?xml version="1.0" encoding="UTF-8"?>
<oimplugins>
<plugins pluginpoint="oracle.iam.scheduler.vo.TaskSupport">
<plugin pluginclass="com.blogspot.ramannanda.schedulers.UserDetailReconTask" version="1.0" name="TrustedSourceReconciliation"/>
</plugins>
</oimplugins>


Note: The actual implementations should filter the data from the target for performance by using something like last modified timestamp.

Posted on Friday, January 04, 2013 by Unknown