TBO Info

Hi All,
I am looking for TBO logic to handle new documents/objects that are created in Documentum. we have specific requirement that we need insert a record whenever a new document/object or version is created in Documentum. I have tried below steps but all have few restriction which I am unable to sort.

1) isNew() method returns true for newly created document/object, where as it returns false for new version.
2) getVStamp() returns 0 for new document, this works for both new document and new version but when a document is being edited/modified after creation in dosave() getVStamp is returning 0 for first edit/modify after document gets created.
3) have put the logic in dosetfile(), only concern with this is that whenever a document /object is checked in as same version isNew() returns false and getVstamp() returns 0. In this method both the cases of new document and new version are getting handled, only problem is that check in same version will trigger the custom logic again for the first time.
4) version label didn't helped in straight way.

so, let me know if there is any method or any way to identify that the object created is new.

Best Answer

  • MYDCTM
    #2 Answer ✓

    Below is the final logic arrived. setFileCalled is the custom attribute placed in doSetFile() method to determine whether the method is called or not.

    and as informed the object id that is available(getObjectId()) in doSetFile() and doSave() is different in case of new version created. I mean the root object id is getting returned in doSetFile() when getObjectId is called.

    if((getVStamp() == 0 && isNew()) || (setFileCalled && !newObjectID.equalsIgnoreCase(getObjectId().getId()) )) {
    custom logic
    }

Answers

  • Why don't you just query your other system prior to insert for r_object_id of the new document or version? This way you dont have to worry about where to put your insert logic within the TBO event.

  • you can test to override method DoSaveAsNew , and add logic inside , and collect what ever information you need

    Tony Qiu
    Opentext ECD - SME

  • @DCTM_Guru said:
    Why don't you just query your other system prior to insert for r_object_id of the new document or version? This way you dont have to worry about where to put your insert logic within the TBO event.

    Hi Johnny,
    Thanks for your reply, I put that as a last option. as for every document I have to hit the DB. there are about 30K + documents that created everyday and further there is a Job which will stamp metadata. so every time the dosave gets called, I don't want to hit the DB to check whether the ID exists or not, rather I am checking if there some thing within Documentum by architecture which will help in letting us know that the document/object is new.

  • @hqiu said:
    you can test to override method DoSaveAsNew , and add logic inside , and collect what ever information you need

    Hi Tony,
    Thanks for your reply. I have tried that option with no luck. The doSaveAsNew() never called when the document is created using BPS, workflow etc.., i.e.., using an import option. as per below link it is only called when a document/object is created from template.

    https://developer-content.emc.com/developer/Component_Exchange/TrapImportTBO.htm

    New Document Using a Template (e.g. Webtop New Document Action)
    The sequence mentioned in an earlier paragraph is not true if a user creates a new document using a template. This is because, document creation from a template is not really an import but a copy of an existing repository document. For example, if a user creates a new document using Webtop, then the above sequence does not get executed. We traced the following sequence when creating a new document using Webtop 5.3.

    TemplateDoc:doUnlink() from template folder
    TemplateDoc:doLink() to target folder
    TemplateDoc:doSaveAsNew() -> returns object id of NewDoc

    let me know if there any other options by architecture of Documentum which help in identifying a document/object as new.

  • IsNew() should work. Alternatively, you can also check if the I_antecedent_id is the same as r_object_id. If its different, then you know its a new version.

  • Tracking changes in TBO has always been difficult and unfortunately client specific. This has been discussed a few times in the EMC forums. Try searching in the migrated forums
    https://communities.opentext.com/forums/categories/DocumentumSupport
    https://communities.opentext.com/forums/categories/documentum_developer

    Alternatively take a read of Andrey take on this problem
    https://blog.documentum.pro/2014/08/07/tracking-changes-in-tbo/

    we have specific requirement that we need insert a record whenever a new document/object or version is created in Documentum

    Is it really necessary to do this work in a TBO? Audit Trail or Full Text Indexing both capture new file events.
    Personally I would argue for copying the full text indexing model,
    1. create user, bob_a_long_listening_for_new_files
    2. with bob_a_long_listening_for_new_files user register for notifications
    3. write code to process all dmi_queue events for that user.

    Brian Dinneen
    ECD Documentum Designated Support Engineer

    image

  • @DCTM_Guru said:
    IsNew() should work. Alternatively, you can also check if the I_antecedent_id is the same as r_object_id. If its different, then you know its a new version.

    Hi Johnny, IsNew() is resulting to "false" in case of new version and a save called on the existing object is also resulting "false" for IsNew(). so by that result I am unable to determine if it is a new version or not. for a completely new document/object IsNew() is returning true.

    I am working on the second suggestion of using other attributes to determine a new version.

  • @Brian Dinneen said:
    Tracking changes in TBO has always been difficult and unfortunately client specific. This has been discussed a few times in the EMC forums. Try searching in the migrated forums
    https://communities.opentext.com/forums/categories/DocumentumSupport
    https://communities.opentext.com/forums/categories/documentum_developer

    Alternatively take a read of Andrey take on this problem
    https://blog.documentum.pro/2014/08/07/tracking-changes-in-tbo/

    we have specific requirement that we need insert a record whenever a new document/object or version is created in Documentum

    Is it really necessary to do this work in a TBO? Audit Trail or Full Text Indexing both capture new file events.
    Personally I would argue for copying the full text indexing model,
    1. create user, bob_a_long_listening_for_new_files
    2. with bob_a_long_listening_for_new_files user register for notifications
    3. write code to process all dmi_queue events for that user.

    Hi Brian,
    Thanks for sharing your insights on this. I will try digging them and for the other options provided, I am unable to find any event which determines that the object is new other than save event which is generated for every dosave call. I am sure that applying a custom logic will work to determine whether or not the document/object is new. However, I am very much looking into Documentum architecture where there is some predefined/existing values/methods which will determine that the object is new to the Docbase.

    Andrey's blog was really informative and provided more insights.

    I tried using the getVStamp() to determine if the object is new or not. this worked well for new document/object and for new version on the same object. However, for the subsequent doSave() call to the same object is also giving 0(zero) which is ideally correct. before super.doSave(). so this is where I am unable to determine if the object is new or not by getVStamp() method.

    isNew() is giving false for new version.

  • After drilling down all these concepts. I am thinking to finalise with the below approach. Please suggest if this holds good for all the cases.

    1) check to see if the object has called dosetfile() - which means a new object or new version or checkin as same version is done
    2) basing on above then I will compare the object id available in dosetfile() with dosave() which is different for new version and same for new object
    3) in do save if the isNew() is true and getVstamp() is 0 then it indicates a new object/document then an entry will be taken to the database as per my requirement
    4) in dosave if the isNew() is false then a dosetfile() method call flag holds true then will compare object id to make an entry to the database, which means a new version is created.

    to illustrate more

    1) isNew()
    2) getVstamp()
    3) custom flag for dosetfile()
    4) object id comparsion

    using data available for above 4 points, I will make the decision in the code to see if the object is new or new version or first time called for dosave() after creation.

  • MYDCTM
    #12 Answer ✓

    Below is the final logic arrived. setFileCalled is the custom attribute placed in doSetFile() method to determine whether the method is called or not.

    and as informed the object id that is available(getObjectId()) in doSetFile() and doSave() is different in case of new version created. I mean the root object id is getting returned in doSetFile() when getObjectId is called.

    if((getVStamp() == 0 && isNew()) || (setFileCalled && !newObjectID.equalsIgnoreCase(getObjectId().getId()) )) {
    custom logic
    }

  • Seem logically. FYI - I have never had to query for vstamp before when writing TBO logic.

  • PanfilovAB
    edited May 2, 2018 #14

    The only point you are correct is checkin may either produce new version or save to the same version.

    to determine whether external logic creates brand new sysobject you need to override both doSave and doSaveEx (overriding only doSave is wrong because in case of IDfSysObject#saveAsNew DFC does not call doSave) and use isNew()

    to determine whether sysobject's content is being changed you need something like:

    ITypedData data = getExtendedData();
    boolean contentChanged = data.hasAttr("_CONTENTS_CHANGED_") && data.getBoolean("_CONTENTS_CHANGED_");
    

    to handle checkin case you need to override doCheckin and use something like:

    protected int getNextVersion(String labels) throws DfException {
        IDfVersionPolicy versionPolicy = getVersionPolicy();
        String minorVersion = versionPolicy.getNextMinorLabel();
        String majorVersion = versionPolicy.getNextMajorLabel();
        String branchVersion = versionPolicy.getBranchLabel();
        String sameVersion = versionPolicy.getSameLabel();
        StringTokenizer tokenizer = new StringTokenizer(labels, ",");
        while (tokenizer.hasMoreTokens()) {
            String versionLabel = tokenizer.nextToken();
            if (Objects.equals(majorVersion, versionLabel)) {
                return IDfCheckinOperation.NEXT_MAJOR;
            }
            if (Objects.equals(minorVersion,versionLabel)) {
                return IDfCheckinOperation.NEXT_MINOR;
            }
            if (Objects.equals(branchVersion,versionLabel)) {
                return IDfCheckinOperation.BRANCH_VERSION;
            }
            if (Objects.equals(sameVersion,versionLabel)) {
                return IDfCheckinOperation.SAME_VERSION;
            }
        }
        return IDfCheckinOperation.NEXT_MINOR;
    }
    

    to determine whether new version is being created or not.

  • The only point you are correct is checkin may either produce new version or save to the same version - all other thoughts are wrong.

    To determine whether external logic creates brand new object you need to override both doSave and doSaveEx (in case of IDfSysObject#saveAsNew DFC does not call doSave) and use isNew()

    To determine whether sysobject's content is being changed you need something like:

    ITypedData data = getExtendedData();
    boolean contentChanged = data.hasAttr("_CONTENTS_CHANGED_") && data.getBoolean("_CONTENTS_CHANGED_");
    

    To handle checkin case you need to override doCheckIn and use something like:

    protected int getNextVersion(String labels) throws DfException {
        IDfVersionPolicy versionPolicy = getVersionPolicy();
        String minorVersion = versionPolicy.getNextMinorLabel();
        String majorVersion = versionPolicy.getNextMajorLabel();
        String branchVersion = versionPolicy.getBranchLabel();
        String sameVersion = versionPolicy.getSameLabel();
        StringTokenizer tokenizer = new StringTokenizer(labels, ",");
        while (tokenizer.hasMoreTokens()) {
            String versionLabel = tokenizer.nextToken();
            if (Objects.equals(majorVersion, versionLabel)) {
                return IDfCheckinOperation.NEXT_MAJOR;
            }
            if (Objects.equals(minorVersion,versionLabel)) {
                return IDfCheckinOperation.NEXT_MINOR;
            }
            if (Objects.equals(branchVersion,versionLabel)) {
                return IDfCheckinOperation.BRANCH_VERSION;
            }
            if (Objects.equals(sameVersion,versionLabel)) {
                return IDfCheckinOperation.SAME_VERSION;
            }
        }
        return IDfCheckinOperation.NEXT_MINOR;
    }
    

    or just to compare current objectId and the result of super.doCheckIn - depends on whether you want to know what is going on before actual checkin or after.

  • The only point you are correct is checkin may either produce new version or save to the same version - all other thoughts are wrong.

    To determine whether external logic creates brand new object you need to override both doSave and doSaveEx (in case of IDfSysObject#saveAsNew DFC does not call doSave) and use isNew()

    To determine whether sysobject's content is being changed you need something like:

    ITypedData data = getExtendedData();
    boolean contentChanged = data.hasAttr("_CONTENTS_CHANGED_") && data.getBoolean("_CONTENTS_CHANGED_");
    

    To handle checkin case you need to override doCheckIn and use something like:

    protected int getNextVersion(String labels) throws DfException {
        IDfVersionPolicy versionPolicy = getVersionPolicy();
        String minorVersion = versionPolicy.getNextMinorLabel();
        String majorVersion = versionPolicy.getNextMajorLabel();
        String branchVersion = versionPolicy.getBranchLabel();
        String sameVersion = versionPolicy.getSameLabel();
        StringTokenizer tokenizer = new StringTokenizer(labels, ",");
        while (tokenizer.hasMoreTokens()) {
            String versionLabel = tokenizer.nextToken();
            if (Objects.equals(majorVersion, versionLabel)) {
                return IDfCheckinOperation.NEXT_MAJOR;
            }
            if (Objects.equals(minorVersion,versionLabel)) {
                return IDfCheckinOperation.NEXT_MINOR;
            }
            if (Objects.equals(branchVersion,versionLabel)) {
                return IDfCheckinOperation.BRANCH_VERSION;
            }
            if (Objects.equals(sameVersion,versionLabel)) {
                return IDfCheckinOperation.SAME_VERSION;
            }
        }
        return IDfCheckinOperation.NEXT_MINOR;
    }
    

    or just to compare current objectId and the result of super.doCheckIn - depends on whether you want to know what is going on before actual checkin or after.

  • The only point you are correct is checkin may either produce new version or save to the same version - all other thoughts are wrong.

    To determine whether external logic creates brand new object you need to override both doSave and doSaveEx (in case of IDfSysObject#saveAsNew DFC does not call doSave) and use isNew()

    To determine whether sysobject's content is being changed you need something like:

    ITypedData data = getExtendedData();
    boolean contentChanged = data.hasAttr("_CONTENTS_CHANGED_") && data.getBoolean("_CONTENTS_CHANGED_");
    

    To handle checkin case you need to override doCheckIn and use something like:

    protected int getNextVersion(String labels) throws DfException {
        IDfVersionPolicy versionPolicy = getVersionPolicy();
        String minorVersion = versionPolicy.getNextMinorLabel();
        String majorVersion = versionPolicy.getNextMajorLabel();
        String branchVersion = versionPolicy.getBranchLabel();
        String sameVersion = versionPolicy.getSameLabel();
        StringTokenizer tokenizer = new StringTokenizer(labels, ",");
        while (tokenizer.hasMoreTokens()) {
            String versionLabel = tokenizer.nextToken();
            if (Objects.equals(majorVersion, versionLabel)) {
                return IDfCheckinOperation.NEXT_MAJOR;
            }
            if (Objects.equals(minorVersion,versionLabel)) {
                return IDfCheckinOperation.NEXT_MINOR;
            }
            if (Objects.equals(branchVersion,versionLabel)) {
                return IDfCheckinOperation.BRANCH_VERSION;
            }
            if (Objects.equals(sameVersion,versionLabel)) {
                return IDfCheckinOperation.SAME_VERSION;
            }
        }
        return IDfCheckinOperation.NEXT_MINOR;
    }
    

    or just to compare current objectId and the result of super.doCheckIn - depends on whether you want to know what is going on before actual checkin or after.

  • The only point you are correct is checkin may either produce new version or save to the same version - all other thoughts are wrong.

    To determine whether external logic creates brand new object you need to override both doSave and doSaveEx (in case of IDfSysObject#saveAsNew DFC does not call doSave) and use isNew()

    To determine whether sysobject's content is being changed you need something like:

    ITypedData data = getExtendedData();
    boolean contentChanged = data.hasAttr("_CONTENTS_CHANGED_") && data.getBoolean("_CONTENTS_CHANGED_");
    

    To handle checkin case you need to override doCheckIn and use something like:

    protected int getNextVersion(String labels) throws DfException {
        IDfVersionPolicy versionPolicy = getVersionPolicy();
        String minorVersion = versionPolicy.getNextMinorLabel();
        String majorVersion = versionPolicy.getNextMajorLabel();
        String branchVersion = versionPolicy.getBranchLabel();
        String sameVersion = versionPolicy.getSameLabel();
        StringTokenizer tokenizer = new StringTokenizer(labels, ",");
        while (tokenizer.hasMoreTokens()) {
            String versionLabel = tokenizer.nextToken();
            if (Objects.equals(majorVersion, versionLabel)) {
                return IDfCheckinOperation.NEXT_MAJOR;
            }
            if (Objects.equals(minorVersion,versionLabel)) {
                return IDfCheckinOperation.NEXT_MINOR;
            }
            if (Objects.equals(branchVersion,versionLabel)) {
                return IDfCheckinOperation.BRANCH_VERSION;
            }
            if (Objects.equals(sameVersion,versionLabel)) {
                return IDfCheckinOperation.SAME_VERSION;
            }
        }
        return IDfCheckinOperation.NEXT_MINOR;
    }
    

    or just to compare current objectId and the result of super.doCheckIn - depends on whether you want to know what is going on before actual checkin or after.

  • The only point you are correct is checkin may either produce new version or save to the same version - all other thoughts are wrong.

    To determine whether external logic creates brand new object you need to override both doSave and doSaveEx (in case of IDfSysObject#saveAsNew DFC does not call doSave) and use isNew()

    To determine whether sysobject's content is being changed you need something like:

    ITypedData data = getExtendedData();
    boolean contentChanged = data.hasAttr("_CONTENTS_CHANGED_") && data.getBoolean("_CONTENTS_CHANGED_");
    

    To handle checkin case you need to override doCheckIn and use something like:

    protected int getNextVersion(String labels) throws DfException {
        IDfVersionPolicy versionPolicy = getVersionPolicy();
        String minorVersion = versionPolicy.getNextMinorLabel();
        String majorVersion = versionPolicy.getNextMajorLabel();
        String branchVersion = versionPolicy.getBranchLabel();
        String sameVersion = versionPolicy.getSameLabel();
        StringTokenizer tokenizer = new StringTokenizer(labels, ",");
        while (tokenizer.hasMoreTokens()) {
            String versionLabel = tokenizer.nextToken();
            if (Objects.equals(majorVersion, versionLabel)) {
                return IDfCheckinOperation.NEXT_MAJOR;
            }
            if (Objects.equals(minorVersion,versionLabel)) {
                return IDfCheckinOperation.NEXT_MINOR;
            }
            if (Objects.equals(branchVersion,versionLabel)) {
                return IDfCheckinOperation.BRANCH_VERSION;
            }
            if (Objects.equals(sameVersion,versionLabel)) {
                return IDfCheckinOperation.SAME_VERSION;
            }
        }
        return IDfCheckinOperation.NEXT_MINOR;
    }
    

    or just to compare current objectId and the result of super.doCheckIn - depends on whether you want to know what is going on before actual checkin or after.

  • @PanfilovAB said:
    The only point you are correct is checkin may either produce new version or save to the same version - all other thoughts are wrong.

    To determine whether external logic creates brand new object you need to override both doSave and doSaveEx (in case of IDfSysObject#saveAsNew DFC does not call doSave) and use isNew()

    To determine whether sysobject's content is being changed you need something like:

    ITypedData data = getExtendedData();
    boolean contentChanged = data.hasAttr("_CONTENTS_CHANGED_") && data.getBoolean("_CONTENTS_CHANGED_");
    

    To handle checkin case you need to override doCheckIn and use something like:

    protected int getNextVersion(String labels) throws DfException {
      IDfVersionPolicy versionPolicy = getVersionPolicy();
      String minorVersion = versionPolicy.getNextMinorLabel();
      String majorVersion = versionPolicy.getNextMajorLabel();
      String branchVersion = versionPolicy.getBranchLabel();
      String sameVersion = versionPolicy.getSameLabel();
      StringTokenizer tokenizer = new StringTokenizer(labels, ",");
      while (tokenizer.hasMoreTokens()) {
          String versionLabel = tokenizer.nextToken();
          if (Objects.equals(majorVersion, versionLabel)) {
              return IDfCheckinOperation.NEXT_MAJOR;
          }
          if (Objects.equals(minorVersion,versionLabel)) {
              return IDfCheckinOperation.NEXT_MINOR;
          }
          if (Objects.equals(branchVersion,versionLabel)) {
              return IDfCheckinOperation.BRANCH_VERSION;
          }
          if (Objects.equals(sameVersion,versionLabel)) {
              return IDfCheckinOperation.SAME_VERSION;
          }
      }
      return IDfCheckinOperation.NEXT_MINOR;
    }
    

    or just to compare current objectId and the result of super.doCheckIn - depends on whether you want to know what is going on before actual checkin or after.

    Hi PanfilovAB,
    Thanks for your valuable information. I am receiving below error when tried getting "_CONTENTS_CHANGED " value.

    11:57:18,542 ERROR [http-nio-8880-exec-7] com.documentum.web.common.Trace - Oper
    ation failed : attribute 'CONTENTS_CHANGED' does not exist
    com.documentum.fc.client.impl.typeddata.NoSuchAttributeException: attribute 'CO
    NTENTS_CHANGED
    ' does not exist
    at com.documentum.fc.client.impl.typeddata.LiteType.getAttr(LiteType.java:171)

    I have few other questions, please let me know the details. It would be helpful to me to learn further.

    1) what exactly this method "getExtendedData()" does ?

    2) Does this indicate object attributes value has changed or not?
    data.hasAttr("CONTENTS_CHANGED")

    3) does this indicate the actual content has changed or not?
    data.getBoolean("CONTENTS_CHANGED");

    4) I have used above code in doSave() , is that fine ?

    Once again thanks for sharing valuable insights.