Guids and Long id values in WebServices - how to extract contentid and revision

There is often confusion in webservices with regards to the long id values that are passed in and returned. These are not the same thing as the content id, and what you get returned can often be a large negative number. In fact these ids are an internal representation of the PSGuid object in the system that is not itself exposed through WebServices.

Often when creating an item you can just pass back the id you got from the system for changes. Problems occur when the item is in a quick edit or other post publish state. The long id value contains information on both the content id and revision id. If an operation like save increases the revision of the item, an ContractViolation error will be thrown if you send back the old id, with the old non editable revision.

If a Guid has a revision id of -1, it is thought of as revisionless and WebServices will always handle the request with the current or edit revision of the item which is often what is required rather than separately trying to request this.

The long value is basically has three parts, type, id and revision stored in a long with a bitmask. I have an example class that can be used to convert a long returned from web services so the values can be manipulated. Using this you can log the proper content id and revision returned by WebServices and also reset the revision id to -1 if you want to modify the current revision of the item.


public class Guid
{
    private long guid;

    public Guid()
    {
    }

    public Guid(int id)
    {
        setId(id);
        setRevision(-1);
        setType(101);
    }

    public Guid(long guid)
    {
        this.guid = guid.longValue();
    }

    public long getGuid()
    {
        return guid;
    }

    public void setGuid(long guid)
    {
        this.guid = guid;
    }

    public int getId()
    {
        return Guid.getId(guid);
    }

    public void setId(int id)
    {
        long mask = 0xffffffff00000000L;
        guid = mask & guid | java.lang.Long.valueOf(id).longValue();
    }

    public int getRevision()
    {
        return getRevision(guid);
    }

    public void setRevision(int revision)
    {
        long mask = 0xffffffffffL;
        guid = mask & guid | java.lang.Long.valueOf(revision).longValue() << 40;
    }

    public int getType()
    {
        return Guid.getType(guid);
    }

    public void setType(int type)
    {
        long mask = 0xffffff00ffffffffL;
        guid = mask & guid | java.lang.Long.valueOf(type).longValue() << 32;
    }

    public String toString()
    {
        return getType()+"-"+getId()+"-"+getRevision();
    }

    public static int getId(long id)
    {
        return (int)(id & 0xffffffffL);
    }

    public static int getRevision(long id)
    {
        return (int)(id >> 40);
    }

    public static int getType(long id)
    {
        return (int)(id >> 32) & 0xff;
    }


}

Hey Stephen,

We may be having a related problem however the twist is that the content type utilizes a child content type.

A description and some vanilla code snippets are include below.

When attempting to update a child item after an item is made public, the update to the child item does not change the value. In general, the situation can be replicated by doing the following:

  1. Create the parent item.
  2. Create the child item.
  3. Load the child item and compare that the value of a field you are going to change is as expected.
  4. Update the child item by changing the field to a new value
  5. Transition the item from the “draft” workflow state to “public”
  6. Get the child item and compare that the value has been changed to the new value – Value will be changed
  7. Update the child item by changing the field to a new value
  8. Transition the item from the “quick edit” workflow state back to “public”
  9. Get the child item and compare that the value has been changed to the new value – Value remains the same (has not changed)

In the Problem.zip archive, I have provided two Junit test cases below (one is a base class). The first test (MobApplicationUpdateIntegrationTest) performs the above scenario on just a parent field and works as you would expect. The other (MobApplicationUpdateRatingIntegrationTest) follows the case described above and will fail on the last test because the value has not changed. MobApplication.java is the wrapper to the content type, and MobUrl.java wraps the child content type.

Any thoughts on what could be wrong would be helpful. We are running on Percussion CM-System 6.7 with an Oracle back end.

problem.zip (9.11 KB)

Update:

Attached is a more simple content type demonstrating the same problem. A single child with a single field.

WithChildIntegrationTest.java.zip (2.92 KB)

The problem may be how you are getting the content id. The original long id is a guid value from the saveItem including the revision.
You are then getting the content id. e.g. the id you see for an item in content explorer using the Guid.getId function. You are casting this to a long and using this in subsequent
calls.


                long id = saveItem(contentService, item);
        checkinItem(contentService, id);
        addFolderChildren(contentService, TARGET_FOLDER, new long[] { id });

        contentId = new Long(Guid.getId(id));

These cannot be cast like this. You can do the following.


Guid guid = new Guid(id)
guid.setRevision(-1); // make this a revisionless guid that to use the latest revision.
contentId = guid.getGuid();