How Do I Modify a Work Item via Get/Post Without OSLC API?
I would like to programmatically modify a work item in a way that is currently unsupported by the OSLC API. It has been suggested that one way of doing this would be to examine the http message traffic using the browser's debugging capabilities and then mimic that traffic to make a change to the work item as if I am a user interacting with a web browser.
I've looked at the web traffic and found the relevant command. However, if I try to send the command again, I get a "Save Conflict" error. The message is:
"Failed saving work item <id> because it did not have the most recent state. Refresh, make additional changes, then save again."
I'm wondering if updating the work item requires a two-part action. I note that when examining the network traffic, the POST messages are always preceded by a "hasWorkItemChanged?" GET request. The response to that request is a Boolean true or false. I'm wondering if it also provides some kind of cookie or header that is used in the subsequent POST. I know there is documentation for the OSLC API that stipulates that you need to set the IfMatch header to make sure you aren't stomping on someone else's changes, but I'm not seeing that header in the web traffic that I've been sniffing. There is a long character token called "LtpaToken2" which might include some kind of information about the state of the work item which may be getting validated, but I can't tell where this token is coming from so I can't mine it.
Has anyone tried to do something like this before? Any help would be appreciated.
4 answers
what you're trying to do sounds like hard work (and is certainly unsupported). Should you manage to get it to work it may well stop working after upgrading to a new version of the product.
If you are trying to make a valid change to a work item and it's just that the OSLC API doesn't support working with that aspect of the data then there are other supported mechanisms you might look at.
If you go to the RTC download pages on jazz.net you will see "Plain Java Client Libraries" and "Plain Java Client Libraries documentation" zip files available for download. There's also the RTC SDK available for download there - it offers a different set of capabilities to the plain java client I believe (I'm not an expert although I have done a little work with them).
Comments
I am revisiting this issue because I am still looking for a better solution than what I developed the last time I tackled this problem. Previously I had implemented a Java Client program that would create the timesheets, but this program would only authenticate on one of our networks (where we used username/password authentication instead of Smart Card).
In recent tests, I believe I have discovered the correct way to get a "False" response to the query "hasWorkItemChanged". The query to check if the work item has changed includes an ItemID (presumably the GUID of the work item), targetLinkItemIds (still unsure what these do), targetLinkTypes (which seems to be hardcoded to com.ibm.team.workitem.linktype.parentworkitem), and a stateId.
The stateId parameters seems to be the important one. It is a GUID that changes every time the work item is modified so this evidently is unrelated to the workflow states.
If you query the work item using the dynaCache, the server will respond with the work item's current stateId. You can then use that stateId in a subsequent "hasWorkItemChanged" query. The dynaCache query looks like this:
https://<server>:<port>/ccm/service/com.ibm.team.workitem.common.internal.rest.IWorkItemRestService/dynaCacheWorkItemStateId?id=<identifier>
I feel like I am on the cusp of success here, but I've hit a roadblock that may prove to be impassable. I was able to "Edit and Resend" the POST request in the Firefox debugger using the latest stateId and I could successfully add timesheet entries. However, it appears that Firefox is automatically including an LtpaToken2 hash in a cookie in that request. The LtpaToken seems to come from the server when you first authenticate and it appears to be necessary in order for the POST to be successful (removing it from the cookie causes the save to fail).
In my code, I have to set the "User-Agent" request header to "CustomInterface" (I think other values like "API" would probably work too) in order to authenticate. If I don't do this, I get a security message from the server saying something like I have tried to access a webpage directly, but must log in first. Unfortunately, when I have the User-Agent cookie set, the server doesn't issue me an LtpaToken when I authenticate. There is a "Set-Cookie" header in the response from the server, but the LtpaToken is ostensibly missing.
So I seem to be at an impasse. I can't save the timesheet without the LtpaToken and I can't get the token unless I authenticate without the User-Agent header, but I can't authenticate without that header.
Has anyone had success with something like this?
Comments
make a request which sends back the sessionid cookie
use the sessionid cookie on the authenticate request and all subsequent requests
my batch file
rem get the cookie
curl -k -c %cookies% "%host%/jts/authenticated/identity" >nul
use the cookie to logon
curl -k -L -b %COOKIES% -c %COOKIES% -d j_username=%USER% -d j_password=%PASSWORD% %host%/jts/authenticated/j_security_check >nul