TDIing out loud, ok SDIing as well

Ramblings on the paradigm-shift that is TDI.

Wednesday, February 6, 2008

If you want TDI to return mutliple values for an Attribute then you
just need to return a JavaScript array:

var mValues = Array();
mValues[0] = "first one";
mValues[1] = "second one";
mValues[2] = "you get the picture";

ret.value = mValues;

This would of course be in a scripted Attribute Map.

If it's just literal values you want to return (like objectClass) you can easily do it like this:

ret.value = ["top",
"person",
"organizationalPersion",
"inetOrgPerson",
"dominoPerson"];

This method does not work when you are adding Attributes to an Entry directly from script. Then you need to either add values to an Attribute and then put it in the Entry:

myAtt = system.newAttribute("Selection");
myAtt.addValue("eenie");
myAtt.addValue("meenie");
myAtt.addValue("mynie moe");
work.setAttribute(myAtt); // works with any Entry

...or you add the Attribute and then the values to the Entry:

ent = system.newEntry();
ent.setAttribute("Selection","eenie");
ent.addAttributeValue("Selection","meenie");
ent.addAttributeValue("Selection","mynie moe");

If instead you want to take a multi-valued Attribute and return it as a comma separated string (as some APIs require), then you could do this using an Attribute Loop and a couple of AttMap components. However, the easiest way is with a snippet of script:

valStr = "";
for (i = 0; i < myMultiVarAttribute.size(); i++)
valStr += ";" + myMultiVarAttribute.getValue(i);
ret.value = valStr.substring(1); // get rid of the first ";"

If you need the values quoted then the script would be:

valStr = "";
for (i = 0; i < myMultiVarAttribute.size(); i++)
valStr += ";\"" + myMultiVarAttribute.getValue(i) + "\"";
ret.value = valStr.substring(1); // get rid of the first ";"

Of course, there could be a double quote (") in the value itself, in which case
you'd need to know how the target system wants this encoded. Perhaps simply by
wrapping the value in single quotes(?) I'd ask Google :)

16 comments:

Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...

Hi Eddie,

The bottom scenario is exactly what I'm after but I can't get it to work...

Do I need an Attribute Value Loop and to use the script in the Script component, within the value loop?

Kind regards,
Tobi

Eddie Hartman said...

@Tobias somehow I published your latest comment twice. I surprise myself sometimes :)

As to your question, you can either use the Attribute value loop and then just the script inside the for-loop. Have you tried to step through your code in the AL Debugger? This often gives insight into what is working (and what is not).

If you're still having a problem then post some example code to the forum and I'll have a look at it.

Side note: since both Entries and Attributes ad Java Collections, you can use the for-in version of these loops:

for (att in work) {
task.logmsg("-->" + att.getName());
for (value in att) {
task.logmsg(" >" + value);
}
}

But I digress :)

Anonymous said...

Hi Eddie,

Sorry, I think I submitted the comment twice... oops.

I couldn't get that to work so I instead added some script to the attribute map on the file connector, against the erroles attribute:

var Array = work.getAttribute("erroles");
var String = "";

if (Array !=null && Array.size()>0)
{
String = Array.getValue(0);
for (i=1;i<Array.size();i++)
{
var role = Array.getValue(i);
String = String + ";" + role;
}
}
return String;

Kind regards,
Tobi

Unknown said...

HI ,

Can you tell me how to modify Multivalued attribute using TDI. If i use removeValue complete array is removed. Tell me the best way of doing it

Eddie Hartman said...

Hi @saipraveen,

Are you trying to remove a specific value from a multi-valued attribute? For example:

// create multi-valued att and add three values
mvalAtt = system.newAttribute("mvalAtt");
mvalAtt.addValue("A");
mvalAtt.addValue("B");
mvalAtt.addValue(42);
mvalAtt.addValue("C");

task.logmsg("mvalAtt: " + mvalAtt); // mvalAtt: [A, B, 42, C]
mvalAtt.removeValue("B"); // remove 'B'
task.logmsg("mvalAtt: " + mvalAtt); // mvalAtt: [A, 42, C]
mvalAtt.removeValue(42); // remove 42
task.logmsg("mvalAtt: " + mvalAtt); // mvalAtt: [A, C]

Unknown said...

removeValue(42) if tried is giving empty array. It is removing complete array. I am using TDI 7.0

Eddie Hartman said...

@saipraveen

Are you setting an Array as the value of an Attribute? If so, then you'll need to use work.getObject('attributeName') to get the array and then do your splicing directly on it. Otherwise, I am not sure how you are seeing this problem. Do you have a script snippet that illustrates your problem? If so, please share and I'll have a look.

Unknown said...

Hi Eddie Hartman,

This is my script used
var Array = work.getAttribute("authoritypersonlist");
var String = "";
//task.logmsg("length of array"+Array.length);

if (Array !=null)
{
String = Array.getValue(0);
for (i=0;i<Array.size();i++)
{
var role = Array.getValue(i);
if (role.indexOf("erglobalid=aaaaaaaaa,ou=0,ou=people,erglobalid=00000000000000000000,ou=Posten,dc=com")!=-1)
{
task.logmsg("remove role");
}
else
{
task.logmsg("new auth===="+role);
//String = String + ";" + role;
var oc = system.newAttribute( "authoritypersonlist");
oc.addValue(role);
ret.value = oc;
return String;
//newRole.addValue(roleArr[i]);
//ret.value=newRole;
}
}
}

suggest me what modifications are required.

Eddie Hartman said...

I would set up the newRole attribute first (before the loop) and return it after. Something like this:

var newRole = system.newAttribute("authoritypersonlist");
var oldRole = work.getAttribute("authoritypersonlist");

if (oldRole != null) {
for (var role in oldRole) {
if (role.indexOf("erglobalid=aaaaaaaaa,ou=0,ou=people,erglobalid=00000000000000000000,ou=Posten,dc=com") < 0) {
newRole.addValue(role);
}
}
}

return newRole;

Unknown said...

Thank you Eddie Hartman for the reply. I can see the newRole values in the loop. But the data in my LDAP is not modified. I have added one dummy value in the loop so that the excluded role is replaced with the new dummy role and the results are satisfactory. Thank you for the help.

Eddie Hartman said...

Just one last thing, good sir, if you are using Update mode to write to LDAP, then you should be able to change values by simply setting the operation (delta) code for each value as either 'add', 'delete' or 'unchanged'. Of course, if you do this, then you also need to set the code for the attribute itself to 'modify' and the same goes for the Entry.

Finally, you can use the LDAP Connector function addAttributeValue, removeAttributeValue, etc. to incrementally manipulate what is in your LDAP directory. I use these extensively - that is how FDS performs efficient group management.

https://www.stephen-swann.co.uk/javadoc/tdi7.1.1/com/ibm/di/connector/LDAPConnector.html#addAttributeValue(java.lang.String,%20java.lang.String,%20java.lang.String)

https://www.stephen-swann.co.uk/javadoc/tdi7.1.1/com/ibm/di/connector/LDAPConnector.html#compare(java.lang.String,%20java.lang.String,%20java.lang.String)

https://www.stephen-swann.co.uk/javadoc/tdi7.1.1/com/ibm/di/connector/LDAPConnector.html#removeAttributeValue(java.lang.String,%20java.lang.String,%20java.lang.String)

PM said...

Hi ,

I think I can relate to this code here and I am stuck at a similar issue . Eddie could you please take a look ?

I have a role multi-valued attribute and want to delete certain roles ( have 6 roles.. if any value is one of those 6 , should be removed from the multi valued attribute )

Can I do this ?

//Code Snippet

var assocroles = work.getAttribute("associaterole");
task.logmsg("---------Assoc Roles are------------"+assocroles);
var rolesArr = new Array(assocroles);

task.logmsg("-----------Deleting specific assoc roles-------------------");
rolesArr.removeValue("roleA");
rolesArr.removeValue("roleB");
rolesArr.removeValue("roleC");
rolesArr.removeValue("roleD");
rolesArr.removeValue("roleE");
rolesArr.removeValue("roleF");

task.logmsg("-----------Returning modified assoc roles-------------------");
return rolesArr;


Thanks ,
PM

Eddie Hartman said...

@PM not quite. You don't want to create a new array passing in your attribute - you'll get an Array with a single value - the Attribute itself. Instead you can use attribute.removeValue(val) to remove the values you want from the Attribute. Note that all values are unique, so adding the same value multiple times will only result in a single value. And when you remove that value, it is gone completely from the Attribute. Hope this helps!

PM said...

@Eddie : Thanks . I corrected the code to use the attribute object and not the array .

I have another issue now . I am using LDAP update to update the multi valued attribute ( i.e strip it off the roles not required ) .

For some reason if the uid is a non - unique parameter , and when the AL finds a duplicate uid , it is throwing "On Multiple Entries" error . I am using uid = $uid as the link criteria on LDAP Update .

Should I use system.skipEntry() / system.ignoreEntry() or should I use a different link criteria which is unique ?


Thanks ,
PM

Eddie Hartman said...

@PM That's up to you. You could either choose a link crit that gives you a single hit, or you could use a Connector Loop for the Lookup - and that let's you easily cycle through all entries found. This can also be done in script via the On Multiple Entries Hook (as described in the TDI Flow Diagrams: https://dl.dropboxusercontent.com/u/375185/Docs/TDI_7.1_FlowDiagrams.pdf

Also, note that we have a Google Forum for asking questions (and searching for answers). A lot easier than here in the comments section of my blog :)

TDI Forum: https://groups.google.com/group/ibm.software.network.directory-integrator/topics?gvc=2