It's all about the answers!

Ask a question

How best to compare attributes in an operation advisor?

Cliff Gardiner (92933) | asked Oct 13 '17, 12:03 p.m.

Hi all (and Ralph in particular :) ),

I have a need to compare two attributes for the same content (a custom contributor attrib against the workitem owner, in this case) and prevent save if they are unequal at a particular state, so I thought I'd generalise this and write an advisor 'Attributes Equal For Type and State'.

My question is how best to achieve this comparison.  My Java knowledge is not strong, so is it safe to simply compare the objects returned from getValue() on the IAttribute objects, or should I determine the object type (I see these types defined in, then compare contents according to the type?

I realise this may be more of a Java question than an API question, but I'd really appreciate a steer here as I feel a bit out of my depth.  Thanks.

Accepted answer

permanent link
Ralph Schoon (63.0k33645) | answered Oct 18 '17, 4:14 a.m.
edited Oct 18 '17, 4:26 a.m.

Hi Cliff,

I think this is one of the many questions that has the ominous answer "It depends".

I don't think there is a general answer that works for all. My experience (and my Java knowledge is also very limited in some areas).

1. Comparing the object usually only works if these Objects implement the necessary interfaces. I rarely use that.I usually at least make sure the object is not null and I can cast to what I expect.
2. If you have an IItemHandle, IItem or IAuditable you can try to get away with the UUID in the handle e.g. and maybe the stateID This would be for all kinds of stuff such as contributors. I have to confess that I only found that out recently and have not really used it that often. To be sure you can resolve the item and get the ID or value or what ever.
3. Strings, Dates etc often requires some kind of comparison/format change etc. so even if equals() works might need further considerations and tests
4. Enumerations, you can compare the literals by ID instead by the values only if the enumeration is the same.
5. Often you have different domains e.g. a user name as string and the contributor, or two different enumerations then you have to resolve and compare the specific values or have a mapping to help with that.

Cliff Gardiner selected this answer as the correct answer

Cliff Gardiner commented Oct 18 '17, 4:29 a.m. | edited Oct 18 '17, 5:07 a.m.

 I can't seem to add a comment but to follow up a little:

Thanks Ralph.  I'd come to the conclusion that there was no simple answer and I'd need to do stuff based on the individual attribute type.  I'm in the early stages of testing the code but my 'attribute comparer' starts like this:

private boolean attribsAreEqual(IAttribute attrib1, IAttribute attrib2, IWorkItem workItem, ParsedConfig parsedConfig, 
IProgressMonitor monitor) throws TeamRepositoryException  {
String attrib1Type = attrib1.getAttributeType();
String attrib2Type = attrib2.getAttributeType();
if (!(attrib1Type.equals(attrib2Type))) {return false;} 

// From
// Uncomment these as they are implemented and tested
switch (attrib1Type) {
case AttributeTypes.SMALL_STRING:
case AttributeTypes.MEDIUM_STRING:
case AttributeTypes.LARGE_STRING:
System.out.println("Object is a STRING type");
String str1 = (String) attrib1.getValue(fAuditableCommon, workItem, monitor);
String str2 = (String) attrib2.getValue(fAuditableCommon, workItem, monitor);
if (str1.equals(str2)) {return true;}
else {
parsedConfig.fMessage = "Work Item "+Integer.toString(workItem.getId())+": String 1 \'"+str1+"\' is not equal to String 2 \'"+str2+"\'";

For contributors I think the only reliable thing to do is to compare user Ids like this and we could have more than one John Smith in the organisation:

case AttributeTypes.CONTRIBUTOR:
System.out.println("Object is a CONTRIBUTOR");
IContributor contrib1 = (IContributor) attrib1.getValue(fAuditableCommon, workItem, monitor); 
IContributor contrib2 = (IContributor) attrib2.getValue(fAuditableCommon, workItem, monitor);
if (contrib1.getUserId().equals(contrib2.getUserId())) {return true;}
else {
parsedConfig.fMessage = "Work Item "+Integer.toString(workItem.getId())+": Contributor 1 \'"+contrib1.getName()+"\' is not the same as Contributor 2 \'"+contrib2.getName()+"\'";

As ever, the devil is in the detail!  No magic bullets ....

Ralph Schoon commented Oct 18 '17, 4:34 a.m.

Yes. Makes sense. The contributor, if they are from within one CCM, the UUID should be OK, otherwise the ID is the best as you mention. Note the ID won't necessarily work across JTS's that is why the LDAP sync also looks at the name.

You might be interested in looking into the Work Item Command Line code, where I use similar approaches. e.g. it is possible to treat various string types similarly (Summary and HTML are different) and so forth.

It can give you at least some ideas of challenges I had....

Ralph Schoon commented Oct 18 '17, 4:38 a.m.

Cliff, note that for getting the UUID e.g. for a contributor object you only need the handle. So you don't always have to resolve the handle. This can save a lot of time.

Cliff Gardiner commented Oct 18 '17, 4:48 a.m.

Thanks again Ralph.  We have a single JTS, a single CCM and validate against LDAP but I see what you mean about multiple instances.  I'll have a play with the UUIDs, anything to improve efficiency is good news.

I'll also have another look at WCL, I think that'll be really helpful.

What would we do without you?

One other answer

permanent link
SEC Servizi (97123458) | answered Oct 18 '17, 4:54 a.m.

If you know the type of the attributes is IContributor, you can simply cast the object instance from getValue() to that type:

IAttribute attribute1 = ...;
IContributor contributor1 = (IContributorattribute1.getValue();
IAttribute attribute2 = ...;
IContributor contributor2 = (IContributorattribute2.getValue();
 and than compare the returned values with method sameItemId():
if (contributor1.sameItemId(contributor2)) {
    // do magic

Ralph Schoon commented Oct 18 '17, 5:05 a.m. | edited Oct 18 '17, 5:11 a.m.

Yes, that is using the UUID. It works for complex items such as IContributors, ITeamAreas,..... within one CCM. Actually from the handle as the UUID is a property of the item handle.

Your answer

Register or to post your answer.