Using a publisher-only JDBC driver in schema-unaware mode



By: ffreitas

February 19, 2010 1:51 pm

Reads: 387

Comments:1

Rating:0

The JDBC driver has several different modes of operation. The schema-unaware mode is when the driver behaves as a pass-through for sql statements, and usually used in a Subscriber-only setup.

The main advantage of the schema-unaware mode is that it does not require any changes to the database, unlike the other driver modes. The main disadvantage is that we won’t have access to all nice features and background work IDM naturally does for us.

For this setup to work the driver must be able to connect to the database, but this can work with any database supported by the JDBC driver. This code requires IDM 3.6.1 or later, since a lot of the logic uses new DirXML-Script tags that were added in that version.

To make the driver more flexible, GCVs will be used to store some information, such as the location users should be placed in eDirectory, SQL statement syntax, Primary Key name and others.

Here is the XML for the GCVs, with some values from my lab:

<?xml version="1.0" encoding="UTF-8"?><configuration-values>
	<definitions>
		<definition display-name="Type of SQL Statement being issued" name="sql.statement.type" type="enum">
			<description>Allows selection between a SELECT statement or a STORED PROCEDURE call.</description>
			<value>select</value>
			<enum-choice display-name="SELECT">select</enum-choice>
			<enum-choice display-name="STORED PROCEDURE">stored</enum-choice>
		</definition>
		<definition display-name="SQL SELECT statement" name="sql.select.text" type="string">
			<description>Enter the SELECT statement here, without a semi-colon at the end</description>
			<value xml:space="preserve">SELECT * FROM lab.usuario</value>
		</definition>
		<definition display-name="STORED PROCEDURE call" name="sql.procedure.name" type="string">
			<description>Enter the SQL statement to call the stored procedure in your database. for example:
CALL lab.exemplo2()</description>
			<value xml:space="preserve">CALL lab.exemplo2</value>
		</definition>
		<definition display-name="Name of the Primary Key column" name="sql.pk.name" type="string">
			<description>enter the name for the column that contains the primary key for the results returned by the SQL statement issued.</description>
			<value xml:space="preserve">idu</value>
		</definition>
		<definition display-name="Name of the column equivalent to Surname" name="sql.sn.name" type="string">
			<description>enter the name for the column that contains the Surname of the user in the results returned by the SQL statement issued.</description>
			<value xml:space="preserve">sobrenome</value>
		</definition>
		<definition display-name="Sulfix value to use in the DirXML-Associations attribute" name="drv.association.sulfix" type="string">
			<description>Sulfix value to use in the DirXML-Associations attribute. Changing this value after the driver already synchronized some users will break the driver's functionality, should be set only on initial deployment.</description>
			<value xml:space="preserve">TABLE=usuario,DB=lab</value>
		</definition>
		<definition display-name="Container where users should be placed in eDirectory" dn-space="dirxml" dn-type="slash" name="drv.user.placement" type="dn">
			<description>Container where users should be placed in eDirectory. Should be entered in slash format.</description>
			<value>vault\users</value>
		</definition>
	</definitions>
</configuration-values>

Since each GCV was created with a brief explanation on its purpose and format, I will move along to the logic pieces needed.

Since when using schema-unaware mode we cannot rely on the JDBC driver shim to perform polling for us, we will need to enable the heartbeat function of the driver and trigger our actions from the heartbeat status message. Another problem is that in schema-unaware mode, the JDBC driver shim does not accept queries to the application. To work around this we will need to use the Source Command Processor to issue our SQL statement from one point in the driver, and treat the results+status message in another part.

The SQL statement that will generate the desired results will be issued from the Publisher Event Transformation Policy set. The reason for this placement is that we will be using the Source Command Processor, and issuing the statement from there will guarantee that the status message+any results to our SQL statement will pass through the Input Transformation Policy set before being evaluated by the IDM engine.

The logic below should be placed in its own policy inside the Publisher Event Transformation Policy set:

<policy xmlns:cmd="http://www.novell.com/nxsl/java/com.novell.nds.dirxml.driver.XdsCommandProcessor">
	<rule>
		<description>generate SQL Query</description>
		<conditions>
			<and>
				<if-operation op="equal">status</if-operation>
				<if-xml-attr name="type" op="equal">heartbeat</if-xml-attr>
				<if-global-variable name="sql.statement.type" op="equal">select</if-global-variable>
			</and>
		</conditions>
		<actions>
			<do-set-local-variable name="sqlstatement">
				<arg-node-set>
					<token-xml-parse>
						<token-text xml:space="preserve">&lt;input xmlns:jdbc="urn:dirxml:jdbc">&lt;jdbc:statement jdbc:type="query">&lt;jdbc:sql></token-text>
						<token-global-variable name="sql.select.text"/>
						<token-text xml:space="preserve">&lt;/jdbc:sql>&lt;/jdbc:statement>&lt;/input></token-text>
					</token-xml-parse>
				</arg-node-set>
			</do-set-local-variable>
			<do-trace-message color="yellow" level="1">
				<arg-string>
					<token-xpath expression="cmd:execute($srcCommandProcessor, $sqlstatement)"/>
				</arg-string>
			</do-trace-message>
			<do-veto/>
		</actions>
	</rule>
	<rule>
		<description>Call stored procedure</description>
		<conditions>
			<and>
				<if-operation op="equal">status</if-operation>
				<if-xml-attr name="type" op="equal">heartbeat</if-xml-attr>
				<if-global-variable name="sql.statement.type" op="equal">stored</if-global-variable>
			</and>
		</conditions>
		<actions>
			<do-set-local-variable name="sqlstatement">
				<arg-node-set>
					<token-xml-parse>
						<token-text xml:space="preserve">&lt;input xmlns:jdbc="urn:dirxml:jdbc">&lt;jdbc:statement>&lt;jdbc:sql></token-text>
						<token-global-variable name="sql.procedure.name"/>
						<token-text xml:space="preserve">&lt;/jdbc:sql>&lt;/jdbc:statement>&lt;/input></token-text>
					</token-xml-parse>
				</arg-node-set>
			</do-set-local-variable>
			<do-trace-message color="yellow" level="1">
				<arg-string>
					<token-xpath expression="cmd:execute($srcCommandProcessor, $sqlstatement)"/>
				</arg-string>
			</do-trace-message>
			<do-veto/>
		</actions>
	</rule>
</policy>

Some important pieces to understand about this logic are:

  • xmlns:cmd (in the policy tag) is a namespace declaration where the cmd namespace to is binded to the XdsCommandProcessor. XdsCommandProcessor is a Java class that will allow us to issue a command back to the database
  • Since the JDBC driver allow us to pass SQL statements directly to the database when they are properly embedded in certain XML, a local variable (named sqlstatement in the example above) is receiving the XML formatted in the correct way. Instead of a hard-coded SQL statement, it is reading the SQL code from a GCV, making it easy to change the statement to match your database needs.
  • Some databases might only expose stored procedures to provide data back. Because of that the logic above has 2 rules, one to handle regular SELECT statements and another to handle STORED PROCEDURES. Which one will be used is also configurable via GCVs
  • The logic above will only issue a command to the other channel, it will not receive nor treat the SQL statement results This is very important, keep it in mind. The logic that will treat the results and issue commands directly to eDirectory will be placed in the Input Transformation Policy set
  • cmd:execute($srcCommandProcessor, $sqlstatement) is where the magic resides. “cmd” is our namespace declared above, “execute” is the function that will send our event to the right location, “$srcCommandProcessor” is the first parameter, and will cause our event to be sent to the Source Command Processor, and “$sqlstatement” is our variable containing a valid nodeset with the command we want to execute.

So far we have our GCVs and also the logic that issues our SQL statement. The result to that statement will be similar to this XML:


<output xmlns:jdbc="urn:dirxml:jdbc">
    <jdbc:result-set jdbc:number-of-rows="1">
        <jdbc:row jdbc:number="1">
            <jdbc:column jdbc:name="idu"
                         jdbc:position="1"
                         jdbc:type="java.sql.Types.BIGINT
                <jdbc:value>l</jdbc:value>
            </jdbc:column>
            <jdbc:column jdbc:name="fname"
                         jdbc:position="2"
                         jdbc:type="java.sql.Types.VARCHAR>
                <jdbc:value>John</jdbc:value>
            </jdbc:column>
            <jdbc:column jdbc:name="lname"
                         jdbc:position="3"
                         jdbc:type="java.sql.Types.VARCHAR>
                <jdbc:value>Doe</jdbc:value>
            </jdbc:column>
        </jdbc:row>
    </jdbc:result-set>
    <status level="success"/>
</output>

As you can see, this is not regular XDS, so we will have to treat it properly in our driver code. XSLT works well to convert this to regular XDS, but instead we will use DirXML-Script logic and some XPATH expressions to parse and treat those results. We will always get a jdbc:result-set element, so we can key off of that. We will always also have the XML attribute jdbc:number-of-rows in our results, and if there are no rows returned from the database that attribute will be set to 0.

Lastly, since this is a return from a command, it only passes the Input Transformation and Schema Mapping policy sets, so we will need to build the logic to account for matching/creation/placement (since we won’t be passing those policy sets). The commands will be issued directly from the Input Transformation policy set, so even the Schema Mapping functionality has to be coded in the driver’s rules.

To properly perform schema (and type) mapping, 2 mapping tables will be used. The tables have to be named as listed, otherwise the driver’s logic will need to be changed to account for their new names.

The first mapping table should be named “edir2db” (without the double-quotes), and its purpose is to map all columns that will be returned to an eDirectory attribute, with the exception of the column used as Primary Key. This example matches a table in my lab, and should be changed to match whichever values come back from your SQL statement. eDirectory attribute names go in the “eDirectory” column, corresponding database column names go in the “database” column. The XML for the mapping table is:

<?xml version="1.0" encoding="UTF-8"?><mapping-table>
	<col-def name="eDirectory"/>
	<col-def name="database"/>
	<row>
		<col>Description</col>
		<col>descricao</col>
	</row>
	<row>
		<col>Given Name</col>
		<col>nome</col>
	</row>
	<row>
		<col>Login Disabled</col>
		<col>disabled</col>
	</row>
	<row>
		<col>Surname</col>
		<col>sobrenome</col>
	</row>
	<row>
		<col>Title</col>
		<col>cargo</col>
	</row>
	<row>
		<col>nspmDistributionPassword</col>
		<col>senha</col>
	</row>
</mapping-table>

The second mapping table should be named “jdbc2type” (without the double-quotes), and its purpose is to map the SQL types returned to eDirectory schema types understod by IDM. There should be no need to change this table. The XML for the mapping table is:

<?xml version="1.0" encoding="UTF-8"?><mapping-table>
	<col-def name="jdbc"/>
	<col-def name="type"/>
	<row>
		<col>java.sql.Types.ARRAY</col>
		<col>string</col>
	</row>
	<row>
		<col>java.sql.Types.BLOB</col>
		<col>octet</col>
	</row>
	<row>
		<col>java.sql.Types.BOOLEAN</col>
		<col>state</col>
	</row>
	<row>
		<col>java.sql.Types.BINARY</col>
		<col>octet</col>
	</row>
	<row>
		<col>java.sql.Types.BIT</col>
		<col>string</col>
	</row>
	<row>
		<col>java.sql.Types.CHAR</col>
		<col>string</col>
	</row>
	<row>
		<col>java.sql.Types.CLOB</col>
		<col>octet</col>
	</row>
	<row>
		<col>java.sql.Types.LONGVARBINARY</col>
		<col>octet</col>
	</row>
	<row>
		<col>java.sql.Types.LONGVARCHAR</col>
		<col>string</col>
	</row>
	<row>
		<col>java.sql.Types.OTHER</col>
		<col>string</col>
	</row>
	<row>
		<col>java.sql.Types.VARBINARY</col>
		<col>octet</col>
	</row>
	<row>
		<col>java.sql.Types.VARCHAR</col>
		<col>string</col>
	</row>
	<row>
		<col>java.sql.Types.BIGINT</col>
		<col>int</col>
	</row>
	<row>
		<col>java.sql.Types.DECIMAL</col>
		<col>string</col>
	</row>
	<row>
		<col>java.sql.Types.DISTINCT</col>
		<col>string</col>
	</row>
	<row>
		<col>java.sql.Types.DOUBLE</col>
		<col>string</col>
	</row>
	<row>
		<col>java.sql.Types.FLOAT</col>
		<col>string</col>
	</row>
	<row>
		<col>java.sql.Types.INTEGER</col>
		<col>int</col>
	</row>
	<row>
		<col>java.sql.Types.NUMERIC</col>
		<col>string</col>
	</row>
	<row>
		<col>java.sql.Types.REAL</col>
		<col>string</col>
	</row>
	<row>
		<col>java.sql.Types.SMALLINT</col>
		<col>int</col>
	</row>
	<row>
		<col>java.sql.Types.TINYINT</col>
		<col>int</col>
	</row>
	<row>
		<col>java.sql.Types.REF</col>
		<col>dn</col>
	</row>
	<row>
		<col>java.sql.Types.DATE</col>
		<col>time</col>
	</row>
	<row>
		<col>java.sql.Types.TIME</col>
		<col>time</col>
	</row>
	<row>
		<col>java.sql.Types.TIMESTAMP</col>
		<col>time</col>
	</row>
</mapping-table>

After creating those mapping tables, we are ready to create the important piece of the puzzle. The concept is simple, if there are 0 rows returned, nothing needs to be done. If there are 1 or more rows returned, the driver need to query the destination container in eDirectory for all users, and then compare what came from the database with what is in eDirectory. Based off of the comparison, the driver will either create a new user, re-associate an existing user, or modify an existing user.

The logic below should be placed in its own policy inside the Publisher Event Transformation Policy set:

<policy xmlns:jdbc="urn:dirxml:jdbc">
	<rule>
		<description>Treat result when 0 rows returned</description>
		<conditions>
			<and>
				<if-operation op="equal">jdbc:result-set</if-operation>
				<if-xml-attr name="jdbc:number-of-rows" op="equal">0</if-xml-attr>
			</and>
		</conditions>
		<actions>
			<do-trace-message color="yellow" level="1">
				<arg-string>
					<token-text xml:space="preserve">  0 rows returned from the SQL statement issued in the Event Transformation Policy set</token-text>
				</arg-string>
			</do-trace-message>
			<do-veto/>
			<do-break/>
		</actions>
	</rule>
	<rule>
		<description>Set local variables for comparison</description>
		<conditions>
			<and>
				<if-operation op="equal">jdbc:result-set</if-operation>
				<if-xml-attr name="jdbc:number-of-rows" op="not-equal">0</if-xml-attr>
			</and>
		</conditions>
		<actions>
			<do-trace-message color="yellow" level="1">
				<arg-string>
					<token-xpath expression="@jdbc:number-of-rows"/>
					<token-text xml:space="preserve"> rows returned from the SQL statement issued in the Event Transformation Policy set</token-text>
				</arg-string>
			</do-trace-message>
			<do-set-local-variable name="watermark">
				<arg-node-set>
					<token-query class-name="User">
						<arg-dn>
							<token-global-variable name="drv.user.placement"/>
						</arg-dn>
					</token-query>
				</arg-node-set>
			</do-set-local-variable>
			<do-set-local-variable name="currentpoll">
				<arg-node-set>
					<token-xpath expression="." notrace="true"/>
				</arg-node-set>
			</do-set-local-variable>
		</actions>
	</rule>
	<rule>
		<description>Issue add and modify events as needed</description>
		<comment xml:space="preserve">Create, modify or re-associate users based on their destination dn and association values.</comment>
		<conditions>
			<and>
				<if-operation op="equal">jdbc:result-set</if-operation>
			</and>
		</conditions>
		<actions>
			<do-for-each>
				<arg-node-set>
					<token-xpath expression="$currentpoll/jdbc:row"/>
				</arg-node-set>
				<arg-actions>
					<do-set-local-variable name="destdn">
						<arg-string>
							<token-text xml:space="preserve">\</token-text>
							<token-global-variable name="dirxml.auto.treename"/>
							<token-text xml:space="preserve">\</token-text>
							<token-global-variable name="drv.user.placement"/>
							<token-text xml:space="preserve">\</token-text>
							<token-xpath expression='$current-node/jdbc:column[@jdbc:name="~sql.sn.name~"]/jdbc:value/text()'/>
							<token-xpath expression='$current-node/jdbc:column[@jdbc:name="~sql.pk.name~"]/jdbc:value/text()'/>
						</arg-string>
					</do-set-local-variable>
					<do-set-local-variable name="association">
						<arg-string>
							<token-text xml:space="preserve">CN=</token-text>
							<token-xpath expression='$current-node/jdbc:column[@jdbc:name="~sql.pk.name~"]/jdbc:value/text()'/>
							<token-text xml:space="preserve">,</token-text>
							<token-global-variable name="drv.association.sulfix"/>
						</arg-string>
					</do-set-local-variable>
					<do-set-local-variable name="fromquery">
						<arg-string>
							<token-xpath expression="$watermark[@src-dn=$destdn]/association/text()"/>
						</arg-string>
					</do-set-local-variable>
					<do-if>
						<arg-conditions>
							<and>
								<if-xpath op="true">$association != $fromquery</if-xpath>
								<if-xpath op="not-true">$watermark[@src-dn=$destdn]</if-xpath>
							</and>
						</arg-conditions>
						<arg-actions>
							<do-set-local-variable name="eventxml" notrace="true">
								<arg-string>
									<token-text xml:space="preserve">&lt;input></token-text>
									<token-text xml:space="preserve">&lt;add class-name="User" dest-dn="$destdn$" event-id="0"></token-text>
									<token-text xml:space="preserve">&lt;association>$association$&lt;/association></token-text>
								</arg-string>
							</do-set-local-variable>
							<do-for-each notrace="true">
								<arg-node-set>
									<token-xpath expression="$current-node/jdbc:column"/>
								</arg-node-set>
								<arg-actions>
									<do-if>
										<arg-conditions>
											<and>
												<if-xpath op="true">$current-node/@jdbc:name != "~sql.pk.name~"</if-xpath>
											</and>
										</arg-conditions>
										<arg-actions>
											<do-set-local-variable name="attrname">
												<arg-string>
													<token-map dest="eDirectory" src="database" table="edir2db">
														<token-xpath expression="$current-node/@jdbc:name"/>
													</token-map>
												</arg-string>
											</do-set-local-variable>
											<do-set-local-variable name="attrtype">
												<arg-string>
													<token-map default-value="string" dest="type" src="jdbc" table="jdbc2type">
														<token-xpath expression="$current-node/@jdbc:type"/>
													</token-map>
												</arg-string>
											</do-set-local-variable>
											<do-set-local-variable name="attrvalue">
												<arg-string>
													<token-xpath expression="$current-node/jdbc:value/text()"/>
												</arg-string>
											</do-set-local-variable>
											<do-if>
												<arg-conditions>
													<and>
														<if-local-variable name="attrtype" op="equal">octet</if-local-variable>
													</and>
												</arg-conditions>
												<arg-actions>
													<do-set-local-variable name="attrvalue">
														<arg-string>
															<token-base64-encode charset="ISO-8859-1">
																<token-local-variable name="attrvalue"/>
															</token-base64-encode>
														</arg-string>
													</do-set-local-variable>
												</arg-actions>
											</do-if>
											<do-set-local-variable name="eventxml">
												<arg-string>
													<token-local-variable name="eventxml"/>
													<token-text xml:space="preserve">&lt;add-attr attr-name="$attrname$"></token-text>
													<token-text xml:space="preserve">&lt;value type="$attrtype$">$attrvalue$&lt;/value></token-text>
													<token-text xml:space="preserve">&lt;/add-attr></token-text>
												</arg-string>
											</do-set-local-variable>
										</arg-actions>
									</do-if>
								</arg-actions>
							</do-for-each>
							<do-set-local-variable name="eventxml" notrace="true">
								<arg-node-set>
									<token-xml-parse>
										<token-local-variable name="eventxml"/>
										<token-text xml:space="preserve">&lt;/add></token-text>
										<token-text xml:space="preserve">&lt;/input></token-text>
									</token-xml-parse>
								</arg-node-set>
							</do-set-local-variable>
							<do-trace-message color="grey" level="1">
								<arg-string>
									<token-text xml:space="preserve"> Creating user $destdn$ with the association value of $association$</token-text>
								</arg-string>
							</do-trace-message>
							<do-set-local-variable name="eventresult">
								<arg-node-set>
									<token-xpath expression="cmd:execute($destCommandProcessor, $eventxml)"/>
								</arg-node-set>
							</do-set-local-variable>
						</arg-actions>
						<arg-actions>
							<do-if>
								<arg-conditions>
									<and>
										<if-local-variable name="fromquery" op="equal"/>
									</and>
								</arg-conditions>
								<arg-actions>
									<do-set-local-variable name="addassociation">
										<arg-node-set>
											<token-xml-parse>
												<token-text xml:space="preserve">&lt;add-association dest-dn="$destdn$"></token-text>
												<token-local-variable name="association"/>
												<token-text xml:space="preserve">&lt;/add-association></token-text>
											</token-xml-parse>
										</arg-node-set>
									</do-set-local-variable>
									<do-trace-message color="grey" level="1">
										<arg-string>
											<token-text xml:space="preserve"> Adding association to $destdn$</token-text>
										</arg-string>
									</do-trace-message>
									<do-set-local-variable name="eventresult">
										<arg-node-set>
											<token-xpath expression="cmd:execute($destCommandProcessor, $addassociation)"/>
										</arg-node-set>
									</do-set-local-variable>
								</arg-actions>
							</do-if>
							<do-set-local-variable name="eventxml" notrace="true">
								<arg-string>
									<token-text xml:space="preserve">&lt;input></token-text>
									<token-text xml:space="preserve">&lt;modify class-name="User" dest-dn="$destdn$" event-id="0"></token-text>
									<token-text xml:space="preserve">&lt;association>$association$&lt;/association></token-text>
								</arg-string>
							</do-set-local-variable>
							<do-for-each notrace="true">
								<arg-node-set>
									<token-xpath expression="$current-node/jdbc:column"/>
								</arg-node-set>
								<arg-actions>
									<do-if>
										<arg-conditions>
											<and>
												<if-xpath op="true">$current-node/@jdbc:name != "~sql.pk.name~"</if-xpath>
											</and>
										</arg-conditions>
										<arg-actions>
											<do-set-local-variable name="attrname">
												<arg-string>
													<token-map dest="eDirectory" src="database" table="edir2db">
														<token-xpath expression="$current-node/@jdbc:name"/>
													</token-map>
												</arg-string>
											</do-set-local-variable>
											<do-set-local-variable name="attrtype">
												<arg-string>
													<token-map default-value="string" dest="type" src="jdbc" table="jdbc2type">
														<token-xpath expression="$current-node/@jdbc:type"/>
													</token-map>
												</arg-string>
											</do-set-local-variable>
											<do-set-local-variable name="attrvalue">
												<arg-string>
													<token-xpath expression="$current-node/jdbc:value/text()"/>
												</arg-string>
											</do-set-local-variable>
											<do-if>
												<arg-conditions>
													<and>
														<if-local-variable name="attrtype" op="equal">octet</if-local-variable>
													</and>
												</arg-conditions>
												<arg-actions>
													<do-set-local-variable name="attrvalue">
														<arg-string>
															<token-base64-encode charset="ISO-8859-1">
																<token-local-variable name="attrvalue"/>
															</token-base64-encode>
														</arg-string>
													</do-set-local-variable>
												</arg-actions>
											</do-if>
											<do-set-local-variable name="eventxml">
												<arg-string>
													<token-local-variable name="eventxml"/>
													<token-text xml:space="preserve">&lt;modify-attr attr-name="$attrname$"></token-text>
													<token-text xml:space="preserve">&lt;remove-all-values/></token-text>
													<token-text xml:space="preserve">&lt;add-value></token-text>
													<token-text xml:space="preserve">&lt;value type="$attrtype$">$attrvalue$&lt;/value></token-text>
													<token-text xml:space="preserve">&lt;/add-value></token-text>
													<token-text xml:space="preserve">&lt;/modify-attr></token-text>
												</arg-string>
											</do-set-local-variable>
										</arg-actions>
									</do-if>
								</arg-actions>
							</do-for-each>
							<do-set-local-variable name="eventxml" notrace="true">
								<arg-node-set>
									<token-xml-parse>
										<token-local-variable name="eventxml"/>
										<token-text xml:space="preserve">&lt;/modify></token-text>
										<token-text xml:space="preserve">&lt;/input></token-text>
									</token-xml-parse>
								</arg-node-set>
							</do-set-local-variable>
							<do-trace-message color="grey" level="1">
								<arg-string>
									<token-text xml:space="preserve"> Modifying user $destdn$</token-text>
								</arg-string>
							</do-trace-message>
							<do-set-local-variable name="eventresult">
								<arg-node-set>
									<token-xpath expression="cmd:execute($destCommandProcessor, $eventxml)"/>
								</arg-node-set>
							</do-set-local-variable>
						</arg-actions>
					</do-if>
				</arg-actions>
			</do-for-each>
		</actions>
	</rule>
	<rule>
		<description>Veto jdbc:result-set</description>
		<comment xml:space="preserve">At this point processing has finished, so we can veto the transaction and let only the original status message pass.</comment>
		<conditions>
			<and>
				<if-operation op="equal">jdbc:result-set</if-operation>
			</and>
		</conditions>
		<actions>
			<do-veto/>
		</actions>
	</rule>
</policy>

Again, since the result will not pass the whole publisher channel, the driver will build well-formed XDS commands for each add/add-association/modify it needs to perform and use the Destination Command Processor to send those commands directly to eDirectory.

Since there is no optimize-modify coded in this example, it will not scale well to large databases, and will require modifications in the code for large datasets. The amount of memory consumed will increase as the dataset increases, so make sure to increase your IDM Java Heap size accordingly.

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

Tags: ,
Categories: Identity Manager, Technical Solutions

Disclaimer: As with everything else at NetIQ Cool Solutions, this content is definitely not supported by NetIQ, so Customer Support will not be able to help you if it has any adverse effect on your environment.  It just worked for at least one person, and perhaps it will be useful for you too.  Be sure to test in a non-production environment.

1 Comment

  1. By:SFDavies

    The last code segment is labelled:
    “The logic below should be placed in its own policy inside the Publisher Event Transformation Policy set:”

    Should that not be “Publisher Input Transformation Policy”?

    Great bit of code though. Thanks very much

Comment