JavaBlog.fr / Java.lu API DCTM,DEVELOPMENT,Documentum,DQL DCTM Documentum : Modify/Change Immutable Document

Documentum : Modify/Change Immutable Document

Hello,

Just a post concerning the immutable document : Documentum doesn’t allow the modification of an immutable document:

DQL> SELECT r_object_id, status, r_immutable_flag FROM my_huo_type WHERE ref_document = 'JavaLu_test_immutable';
r_object_id       status  r_immutable_flag
================  ======  ====== 
090xxxxxxxxxxxx8  1  	  1                   
(1 rows affected)

If, we try to change the status attribute of this document, we will obtain the following error:

DQL> UPDATE my_huo_type OBJECTS set status=6 where r_object_id ='090xxxxxxxxxxxx8';
[DM_QUERY_F_UP_SAVE]fatal:  "UPDATE:  An error has occurred during a save operation."
[DM_SYSOBJECT_E_CANT_SAVE_IMMUTABLE]error:  "Cannot save MY_DOC_OBJ_NAME_1 since it is immutable."

However, even on an immutable document, some attributes/actions could be done: change of ACL, content moving, modification done via SQL instructions like last modification date,…etc.

When the above error occurs, the simple « workarround solution » is:
1. set the r_immutable_flag attribute to FALSE,
2. do the modifications on the document,
3. finally set again the r_immutable_flag attribute to its previous TRUE value.

 
Here, the steps of this « workarround solution »:
1. Check the value of r_immutable_flag attributwe of the document :

DQL> SELECT r_immutable_flag from my_huo_type where r_object_id ='090xxxxxxxxxxxx8';
r_immutable_flag  
1  

 
 
2. IF r_immutable_flag=TRUE OR r_immutable_flag=1 THEN,
Solution 1 : via DQL

  • Update the flag r_immutable_flag=FALSE via DQL
    DQL> EXECUTE exec_sql WITH query= 'update dm_sysobject_s set r_immutable_flag=0 where r_object_id= ''090xxxxxxxxxxxx8''';
    OR
    DQL> EXECUTE exec_sql WITH query= 'update dm_sysobject_s set r_immutable_flag=''F'' where r_object_id= ''090xxxxxxxxxxxx8''';
    
  • Update the target « status » attribute via DQL
    DQL> UPDATE my_huo_type OBJECTS set status=6 where r_object_id ='090xxxxxxxxxxxx8';
    
  • Update the flag r_immutable_flag=TRUE (previous value) via DQL
    DQL> EXECUTE exec_sql WITH query= 'update dm_sysobject_s set r_immutable_flag=1 where r_object_id= ''090xxxxxxxxxxxx8''';
    OR
    DQL> EXECUTE exec_sql WITH query= 'update dm_sysobject_s set r_immutable_flag=''T'' where r_object_id= ''090xxxxxxxxxxxx8''';
    

 
 
Solution 2 : via API

  • Update the flag r_immutable_flag=FALSE via API
    APi>set,c,090xxxxxxxxxxxx8,r_immutable_flag
    0
    ...
    OK
    
  • Update the target « status » attribute via API
    API>set,c,090xxxxxxxxxxxx8,status
    6
    ...
    OK
    
  • Update the flag r_immutable_flag=TRUE (previous value) via API
    API>set,c,090xxxxxxxxxxxx8,r_immutable_flag
    1
    ...
    OK
    
  • Save the document via API
    API>save,c,090xxxxxxxxxxxx8
    ...
    OK
    

 
 
Solution 3 : Change the behaviour of docbase in order to ignore value of the r_immutable_flag flag when the ‘status’ attribute of the type ‘my_huo_type’ is modified.

select r_object_id, type_name, label_text, nls_key, i_ignore_immutable, ignore_immutable from  dmi_dd_attr_info where type_name = 'my_huo_type' and attr_name IN ('status','status_free_to_change');

r_object_id = 6axxxxxxxxxxxxxxa0
type_name = my_huo_type
label_text = status
nls_key = en
i_ignore_immutable = 0
ignore_immutable = 0

r_object_id = 6ayyyyyyyyyyyyyy87
type_name = my_huo_type
label_text = status_free_to_change
nls_key = en
i_ignore_immutable = 0 
ignore_immutable = 1

The value of the dmi_dd_attr_info.ignore_immutable determines if the attribute is free for changes even if the object is immutable. In either case i_ignore_immutable doesn’t make any difference. In the above example the status_free_to_change attribute is free for changes.

update dmi_dd_attr_info object set ignore_immutable = T where type_name = 'my_huo_type' and attr_name = 'status';

 
 
3. ELSE (IF r_immutable_flag=FALSE OR r_immutable_flag=0 THEN),

  • See the logs,
  • Check if the target version of document is lock :
    # Get the all versions
    DQL>SELECT mytype.r_version_label, mytype.r_lock_owner, mytype.r_object_id, mytype.status, mytype.acl_domain, mytype.acl_name 
    FROM my_huo_type (ALL) mytype WHERE mytype.ref_doc = 'JavaLu_test_immutable'  
    order by r_creation_date desc, r_version_label desc ENABLE (ROW_BASED);
    ...
    
    # unlock the version
    API>unlock,c,090xxxxxxxxxxc1
    ...etc
    

 
 
In practice via DFC / Java code:
 
EXAMPLE 1 : Simple example

		for (String documentId : documentIds) {
			try {
				LOGGER.info(documentId + " : update content (" + countCurrent + "/" + countTotal + ")... ");
				IDfDocument document = (IDfDocument) session.getObject(new DfId(documentId));
				boolean isImmutable = document.isImmutable();
				if (isImmutable) {
					document.setBoolean("r_immutable_flag", false);
					document.save();
				}
				
				document.setSubject(SUBJECT_ANONYMIZED);
				document.setContentType("pdf");
				document.setFile(docFolder + File.separator + canal + "-encrypted.pdf");
				document.save();
				
				if (isImmutable) {
					document.setBoolean("r_immutable_flag", true);
					document.save();
				}
				LOGGER.info(documentId + " : [OK]");
			} catch(Exception e) {
				LOGGER.error(documentId + " : [KO: error to update content]", e);
			}
			countCurrent++;
		}

 
 
EXAMPLE 2 : Complete example with transaction and rollback on last modifier, last modification date and immutable flag

	private void setPreviousValuesOfLastModifAttributesBySQL(IDfSession session, String currObjectId, IDfTime previousModifyDateTime, String previousModifier) throws Throwable{
		StringBuilder sql = new StringBuilder();
		sql.append("UPDATE ").append(session.getDocbaseOwnerName()).append(".DM_SYSOBJECT_S");
		sql.append(" SET ");
		sql.append(" R_MODIFIER = '").append(previousModifier).append("',");
		DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
		dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
		sql.append(" R_MODIFY_DATE = to_date('").append(dateFormat.format(previousModifyDateTime.getDate())).append("', 'DD-MM-YYYY HH24:MI:SS')");
		sql.append(" WHERE R_OBJECT_ID = '").append(currObjectId).append("'");
		IDfApplyExecSQL dfApplyExecSQL = (IDfApplyExecSQL) DfAdminCommand.getCommand(DfAdminCommand.APPLY_EXEC_SQL);
		dfApplyExecSQL.setQuery(sql.toString());
		IDfCollection coll = dfApplyExecSQL.execute(session);
		try {
			if (coll.next()) {
				IDfValue dfValue = coll.getValueAt(0);
				if (!dfValue.asBoolean()) {
					throw new RuntimeException("");
				}
			} else {
				throw new RuntimeException("");
			}
		} finally {
			if(coll!=null){
				coll.close();
			}
		}
	}

…..

	
	private void setValuesToImmutableAttributeBySQL(IDfSession session, String currObjectId, boolean bValue) throws Throwable{
		StringBuilder sql = new StringBuilder();
		sql.append("UPDATE ").append(session.getDocbaseOwnerName()).append(".DM_SYSOBJECT_S");
		sql.append(" SET ");
		sql.append(" R_IMMUTABLE_FLAG = '").append(bValue?"1":"0").append("' ");
		sql.append(" WHERE R_OBJECT_ID = '").append(currObjectId).append("'");
		IDfApplyExecSQL dfApplyExecSQL = (IDfApplyExecSQL) DfAdminCommand.getCommand(DfAdminCommand.APPLY_EXEC_SQL);
		dfApplyExecSQL.setQuery(sql.toString());
		IDfCollection coll = dfApplyExecSQL.execute(session);
		try {
			if (coll.next()) {
				IDfValue dfValue = coll.getValueAt(0);
				if (!dfValue.asBoolean()) {
					throw new RuntimeException("");
				}
			} else {
				throw new RuntimeException("");
			}
		} finally {
			if(coll!=null){
				coll.close();
			}
		}
	}

…..

			IDfSession session = ...;
			IDfCollection documents = ...;
			
			while (documents.next()) {
				String currObjectId = null;
				boolean previousImmutableFlag = false;

				boolean isTransactionalSession = false;
				boolean noErrorWithCurrentDocument = false;
				try {
					if (!session.isTransactionActive()) {
						session.beginTrans();
						isTransactionalSession = true;
					}
					
					currObjectId = documents.getString("r_object_id");
					// Get and store the value of r_modify_date AND r_modifier BEFORE the changes
					IDfTime previousModifyDateTime = documents.getTime("r_modify_date");
					String previousModifier = documents.getString("r_modifier");
					String aContentType = documents.getString("a_content_type"); // excel12book
					previousImmutableFlag = documents.getBoolean("r_immutable_flag");

					//Mise à jour du flag « r_immutable_flag=FALSE » via SQL
					if(previousImmutableFlag){
						setValuesToImmutableAttributeBySQL(session, currObjectId, false);
					}

					// #### Appying changements 
					//....
					
					// Setting of the previous value for r_modify_date AND r_modifier because the attachment of aspect needs a SAVE action on document.
					// So, Content server overrides r_modifer and r_modify_date informations. 
					setPreviousValuesOfLastModifAttributesBySQL(session, currObjectId, previousModifyDateTime, previousModifier);
					
					noErrorWithCurrentDocument = true;
				} catch(Throwable th) {
					Throwable rootCause = ExceptionUtils.getRootCause(th);
					if(rootCause!=null){
						rootCause.printStackTrace(pw);
					}else{
						th.printStackTrace(pw);
					}
					throw th;
				}finally{
					//Mise à jour du flag « r_immutable_flag=TRUE » via SQL
					if(previousImmutableFlag){
						setValuesToImmutableAttributeBySQL(session, currObjectId, true);
					}

					if (isTransactionalSession) {
						if (noErrorWithCurrentDocument) {
							session.commitTrans();
						} else {
							session.abortTrans();
						}
					}
				}
			}// end-while

That’s all!!!!

Huseyin OZVEREN

Leave a Reply

Your email address will not be published.

Time limit is exhausted. Please reload CAPTCHA.

Related Post

Documentum : Audit trail entries dm_audittrail / SessionConfig / application_codeDocumentum : Audit trail entries dm_audittrail / SessionConfig / application_code

Hi, After my previous posts concerning the Documentum audit trail entries (dm_audittrail) http://www.javablog.fr/documentum-creation-of-audit-trail-entries-dm_audittrail.html and http://www.javablog.fr/deleting-of-audit-trail-entries-dm_audittrail.html, here, I would like to expose a solution in order to force content server to