Use the search(DataObject) method and the ChangeControl DataObject to query the federated repository for changed entities from a certain checkpoint onwards.
The ChangeControl DataObject differentiates a search for changed entities from a normal search operation. Each entity that is returned as a result of the search is associated with the changeType property.
The changeType property of the Entity DataObject is an optional property that is set only in response to a search for changed entities. The changeType property describes the type of change that occurred, which could be adding a new entity, modifying an existing entity, deleting an entity, or renaming an entity.
The valid values and string constants of the changeType property are add (for CHANGETYPE_ADD), delete (for CHANGETYPE_DELETE), modify (for CHANGETYPE_MODIFY), and rename (for CHANGETYPE_RENAME).
For added, modified, and renamed entities, the current entity in the repository is returned. For deleted entities, only the entity identifier, consisting of the external name and unique name is returned. (In IBM® Tivoli® Directory Server version 6.1 and prior, the repository specific UUID is not returned as part of the entity identifier, whereas in IBM Tivoli Directory Server version 6.2 and above, the entity identifier includes the repository specific UUID along with the external name and unique name.) The repository checkpoint is agnostic of change types and the search base. The checkpoint applies to the whole repository.
For IBM Tivoli Directory Server, also ensure that the fix for Authorized Program Analysis Report (APAR) 1IO10107 is installed.
Consider a scenario where a virtual member manager application is configured with three repositories: IBM Tivoli Directory Server, Active Directory, and a file repository. When the application is in sync with virtual member manager, the checkpoint is retrieved and saved. This saved checkpoint is used in the ChangeControl during the next sync interval. The following sample code retrieves the current checkpoint:
DataObject root = com.ibm.websphere.wim.util.SDOHelper.createRootDataObject();
com.ibm.websphere.wim.util.SDOHelper.createControlDataObject(root, WIM_NS_URI, DO_CHANGE_CONTROL);
return service.search(root);
For this particular example, the steps in the process for handling a search for changed entities are explained here.
The virtual member manager client application sends a ChangeControl without any checkpoint during the first search for changed entities. The input data graph is shown here.
<?xml version="1.0" encoding="UTF-8"?>
<sdo:datagraph xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sdo="commonj.sdo" xmlns:wim="http://www.ibm.com/websphere/wim">
<wim:Root>
<wim:controls xsi:type="wim:ChangeControl" changeTypes="*"/>
</wim:Root>
</sdo:datagraph><?xml version="1.0" encoding="UTF-8"?>
<sdo:datagraph xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sdo="commonj.sdo" xmlns:wim="http://www.ibm.com/websphere/wim">
<wim:Root>
<wim:controls xsi:type="wim:ChangeControl"/>
</wim:Root>
</sdo:datagraph>
<?xml version="1.0" encoding="UTF-8"?>
<sdo:datagraph xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sdo="commonj.sdo" xmlns:wim="http://www.ibm.com/websphere/wim">
<wim:Root>
<wim:controls xsi:type="wim:ChangeResponseControl">
<wim:checkPoint>
<wim:repositoryId>TDS_LDAP</wim:repositoryId>
<wim:repositoryCheckPoint>21</wim:repositoryCheckPoint>
</wim:checkPoint>
<wim:checkPoint>
<wim:repositoryId>AD_LDAP</wim:repositoryId>
<wim:repositoryCheckPoint>41</wim:repositoryCheckPoint>
</wim:checkPoint>
</wim:controls>
</wim:Root>
</sdo:datagraph>
During a subsequent search for changed entities, this consolidated checkpoint is passed back to virtual member manager and the profile manager interface is responsible for passing the appropriate checkpoint to the corresponding adapter.
To copy the checkpoint from the previous ChangeResponseControl to the input ChangeControl, add the following sample code to your application code and replace the variables with the actual values that you want to use:
/**
* Get the current checkpoint for the repositories
* @return DataObject: DataObject with ChangeResponseControl containing the checkpoints
* for the repositories that support change tracking
*/
public DataObject searchGetCurrentCheckpoint() throws WIMException
{
DataObject root = com.ibm.websphere.wim.util.SDOHelper.createRootDataObject();
com.ibm.websphere.wim.util.SDOHelper.createControlDataObject(root, WIM_NS_URI, DO_CHANGE_CONTROL);
return service.search(root);
}
/**
* Search the changed entities since the checkpoint returned by searchGetCurrentCheckpoint
* @param prevRoot: DataObject returned from searchGetCurrentCheckpoint
* @return DataObject: DataObject with changed entities and ChangeResponseControl
*/
public DataObject searchGetChangedEntities(final DataObject prevRoot) throws WIMException
{
DataObject root = com.ibm.websphere.wim.util.SDOHelper.createRootDataObject();
DataObject changeCtrl = com.ibm.websphere.wim.util.SDOHelper.createControlDataObject(root, null, DO_CHANGE_CONTROL);
changeCtrl.setString(SchemaConstants.PROP_SEARCH_EXPRESSION, "@xsi:type='PersonAccount'");
changeCtrl.getList(SchemaConstants.PROP_PROPERTIES).add("uid");
changeCtrl.getList(SchemaConstants.PROP_PROPERTIES).add("cn");
changeCtrl.getList(SchemaConstants.PROP_PROPERTIES).add("sn");
changeCtrl.getList(PROP_CHANGETYPES).add(SchemaConstants.CHANGETYPE_ALL);
com.ibm.websphere.wim.util.SDOHelper.createChangeCtrlFromChangeRespCtrl(root, prevRoot);
return service.search(root);
}
/**
* Method to call searchGetCurrentCheckpoint and searchChangedEntities
*/
public void search() throws WIMException
{
/* Get the current checkpoint */
DataObject result = searchGetCurrentCheckpoint();
/* Here add, modify, rename, delete some entities */
/* Search for the changed entities since the checkpoint returned by searchGetCurrentCheckpoint */
result = searchGetChangedEntities(result);
}
In the previous code, the search() method first calls the searchGetCurrentChekpoint() method to retrieve the current checkpoints. The result returned by searchGetCurrentCheckpoint() is passed to the second method, searchGetChangedEntities(). It uses the SDOHelper.createChangeCtrlFromChangeRespCtrl() utility method to obtain an updated ChangeControl containing the saved checkpoint from the ChangeResponseControl returned by searchGetCurrentCheckpoint.
The input data graph for a subsequent search containing the saved checkpoint is shown here:
<?xml version="1.0" encoding="UTF-8"?>
<sdo:datagraph xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sdo="commonj.sdo" xmlns:wim="http://www.ibm.com/websphere/wim">
<wim:Root>
<wim:controls xsi:type="wim:ChangeControl" expression="@xsi:type='PersonAccount' and cn='tuser*'">
<wim:checkPoint>
<wim:repositoryId>TDS_LDAP</wim:repositoryId>
<wim:repositoryCheckPoint>21</wim:repositoryCheckPoint>
</wim:checkPoint>
<wim:checkPoint>
<wim:repositoryId>AD_LDAP</wim:repositoryId>
<wim:repositoryCheckPoint>41</wim:repositoryCheckPoint>
</wim:checkPoint>
<wim:changeTypes>add</wim:changeTypes>
</wim:controls>
</wim:Root>
</sdo:datagraph>
If three new entities are added in IBM Tivoli Directory Server and two new entities are added in Active Directory, the resulting output data graph is shown here:
<?xml version="1.0" encoding="UTF-8"?>
<sdo:datagraph xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sdo="commonj.sdo" xmlns:wim="http://www.ibm.com/websphere/wim">
<wim:Root>
<wim:entities xsi:type="wim:PersonAccount">
<wim:identifier externalName="cn=tuser1,o=tds" repositoryId="TDS_LDAP" uniqueId="13f1c1c8-ff43-433c-b0ca-02fb5a56b522"
uniqueName="cn=tuser1,o=tds"/>
<wim:changeType>add</wim:changeType>
</wim:entities>
<wim:entities xsi:type="wim:PersonAccount">
<wim:identifier externalName="cn=tuser3,o=tds" repositoryId="TDS_LDAP" uniqueId="25641e84-b17b-48ee-b9cb-d7eea2496005"
uniqueName="cn=tuser3,o=tds"/>
<wim:changeType>add</wim:changeType>
</wim:entities>
<wim:entities xsi:type="wim:PersonAccount">
<wim:identifier externalName="cn=tuser5,o=tds" repositoryId="TDS_LDAP" uniqueId="a3316b8d-f496-4a5b-93eb-ba59f47aa2ab"
uniqueName="cn=tuser5,o=tds"/>
<wim:changeType>add</wim:changeType>
</wim:entities>
<wim:entities xsi:type="wim:PersonAccount">
<wim:identifier externalName="CN=tuser4,DC=vmm-server11,DC=in,DC=ibm,DC=com"
repositoryId="AD_LDAP" uniqueId="855c13b14a2e5e448af0699d4b2aaf47" uniqueName="CN=tuser4,o=ad"/>
<wim:changeType>add</wim:changeType>
</wim:entities>
<wim:entities xsi:type="wim:PersonAccount">
<wim:identifier externalName="CN=tuser2,DC=vmm-server11,DC=in,DC=ibm,DC=com"
repositoryId="AD_LDAP" uniqueId="725199db56ac8342b7c6a08ae3cb93e3" uniqueName="CN=tuser2,o=ad"/>
<wim:changeType>add</wim:changeType>
</wim:entities>
<wim:controls xsi:type="wim:ChangeResponseControl">
<wim:checkPoint>
<wim:repositoryId>TDS_LDAP</wim:repositoryId>
<wim:repositoryCheckPoint>24</wim:repositoryCheckPoint>
</wim:checkPoint>
<wim:checkPoint>
<wim:repositoryId>AD_LDAP</wim:repositoryId>
<wim:repositoryCheckPoint>43</wim:repositoryCheckPoint>
</wim:checkPoint>
</wim:controls>
</wim:Root>
</sdo:datagraph
The results of a search for changed entities differ between IBM Tivoli Directory Server and Active Directory. Two important differences are explained here.
The renamed entity is returned with the changeType rename. To identify the original entity, the virtual member manager client application must associate between the uniqueID (as obtained from the ibm-entryUUID attribute) of the old and new entity.
The renamed entity is returned with the changeType modify. The virtual member manager client application can identify a rename operation when it encounters a modify operation for a distinguished name (DN) that does not exist in its copy. However, a modify operation is reported even for a new DN that is not yet in the copy of the application. A modify operation is reported even if an entity is added and modified in the same sync cycle. Therefore, the virtual member manager client application must associate between the unique ID (as obtained from the objectGUID attribute of Active Directory) of the old and new entity. If no uniqueID is found, then it is an addition, else it is a rename operation on an existing entity.
The final version of the changed entity is reported as many times as there have been changes on the entity in the sync cycle, with the changeType modify. For example, if there are four modifications to an entity within the same sync cycle, then the final version of the modified entity is returned four times as the changed entity with changeType modify. An exception to this case is when the entity is deleted later within the same sync cycle. In this case, any other operation on the entity before it was deleted is ignored and not returned to the virtual member manager application.
The attribute cache maintained by virtual member manager is updated each time you search for changed entities, even if an entity is modified and then deleted in the same sync cycle.
Only the final update to the entity is returned. For example, if an entity was added and deleted in the same sync cycle, the virtual member manager client receives a delete changeType for an entity that is not present in its copy. In this case, the virtual member manager application must include the logic to ignore the change notifications.
The attribute cache maintained by virtual member manager is updated each time you search for changed entities. However, the attribute cache is not updated if an entity is changed and then deleted from the repository in the same sync cycle.