I need to convert many objects to another type and then set their attributes. To reduce the number of RPCs I use session.getObjectsByQuery() to fetch 100 objects after they're converted, then I call setString() and save().
For some reason, after I call save(), the object attributes that belong to the type I converted them to and that I have just set become blank. getString() returns an empty string. This only happens if the object with the old type existed before I connected to the docbase. I suspect an issue with the DFC cache and I'd like to invalidate it for certain object ids before calling getObjectsByQuery().
Here's the demo program:
import java.io.PrintStream;
import java.util.Objects;
import com.documentum.fc.client.DfClient;
import com.documentum.fc.client.DfQuery;
import com.documentum.fc.client.IDfClient;
import com.documentum.fc.client.IDfEnumeration;
import com.documentum.fc.client.IDfQuery;
import com.documentum.fc.client.IDfSession;
import com.documentum.fc.client.IDfSessionManager;
import com.documentum.fc.client.IDfSysObject;
import com.documentum.fc.client.IDfType;
import com.documentum.fc.common.DfDocbaseConstants;
import com.documentum.fc.common.DfException;
import com.documentum.fc.common.DfLoginInfo;
import com.documentum.fc.common.IDfAttr;
import com.documentum.fc.common.IDfId;
import com.documentum.fc.common.IDfLoginInfo;
public final class AaaTestChangeType {
private enum GetMethod {
BY_QUERY,
BY_QUALIFICATION,
BY_ID
}
private static final GetMethod GET_METHOD = GetMethod.BY_QUERY;
private static final boolean ALWAYS_NEW_SM = true;
private static final String NEWVAL = "newval";
private static final String TYPE_NAME = "testchangetype";
private static final String COND = "where object_name = '" + TYPE_NAME + "'";
private static final String ATTR = "s";
private static final IDfClient CL;
private static final PrintStream OUT = System.out; /* NOSONAR */
private static String docbase;
private static String username;
private static String password;
private static IDfSessionManager sm;
private static IDfId oid;
private AaaTestChangeType() {}
static {
try {
CL = DfClient.getLocalClient();
} catch (final DfException e) {
throw new RuntimeException(e);
}
}
public static void main(final String[] args) throws Exception {
if (args.length != 3) {
OUT.println("Usage: programname docbase username password");
System.exit(1);
}
docbase = args[0];
username = args[1];
password = args[2];
IDfSession session;
session = connect();
createObject(session);
disconnect(session);
OUT.println();
session = connect();
changeTypeAndUpdate(session);
disconnect(session);
}
private static void disconnect(final IDfSession session) throws DfException {
session.getSessionManager().release(session);
}
private static IDfSession connect() throws DfException {
if (sm == null || ALWAYS_NEW_SM) {
sm = CL.newSessionManager();
final IDfLoginInfo info = new DfLoginInfo();
info.setUser(username);
info.setPassword(password);
sm.setIdentity(docbase, info);
}
return sm.getSession(docbase);
}
private static void createObject(final IDfSession session) throws DfException {
OUT.println("deleting previously created objects");
execQuery(session, "delete dm_sysobject objects " + COND);
mkType(session);
OUT.println("newObject()");
final IDfSysObject obj = (IDfSysObject) session.newObject("dm_sysobject");
oid = obj.getObjectId();
obj.setObjectName(TYPE_NAME);
obj.link("/Temp");
OUT.println("save()");
obj.save();
}
private static void changeTypeAndUpdate(final IDfSession session) throws DfException {
// session.beginTrans()
try {
execQuery(session, "change dm_sysobject objects to " + TYPE_NAME + " " + COND);
final IDfSysObject obj = getObject(session);
OUT.println(ATTR + ": " + obj.getString(ATTR));
OUT.println("setString()");
obj.setString(ATTR, NEWVAL);
checkVal(obj);
OUT.println("save()");
obj.save();
checkVal(obj);
} finally {
if (session.isTransactionActive()) {
session.abortTrans();
}
}
}
private static IDfSysObject getObject(final IDfSession session)
throws DfException {
switch (GET_METHOD) {
case BY_ID:
return getObjectById(session);
case BY_QUALIFICATION:
return getObjectByQualification(session);
case BY_QUERY:
return getObjectByQuery(session);
default:
throw new UnsupportedOperationException();
}
}
private static IDfSysObject getObjectById(final IDfSession session) throws DfException {
return (IDfSysObject) session.getObject(oid);
}
private static IDfSysObject getObjectByQualification(
final IDfSession session) throws DfException {
OUT.println("getObjectByQualification()");
return (IDfSysObject) session.getObjectByQualification(TYPE_NAME + " " + COND);
}
private static IDfSysObject getObjectByQuery(final IDfSession session)
throws DfException {
final IDfType type = session.getType(TYPE_NAME);
final AllAttrsObjectQueryBuilder qb = new AllAttrsObjectQueryBuilder(type);
qb.resetLength();
qb.getSb().append(COND);
final String dql = qb.appendOrderBy().toString();
OUT.println(dql);
OUT.println("getObjectsByQuery()");
final IDfEnumeration enumeration = session.getObjectsByQuery(dql, null);
return (IDfSysObject) enumeration.nextElement();
}
private static void checkVal(final IDfSysObject obj) throws DfException {
final String val = obj.getString(ATTR);
OUT.println(ATTR + ": " + val);
if (!NEWVAL.equals(val)) {
throw new RuntimeException("Expected: '" + NEWVAL + "', got: '" + val + "'");
}
}
private static void mkType(final IDfSession session) throws DfException {
final IDfType type = session.getType(TYPE_NAME);
if (type == null) {
OUT.println("type not found");
execQuery(
session,
"create TYPE " + TYPE_NAME + " ( " + ATTR
+ " string(1000) ) WITH SUPERTYPE dm_sysobject publish");
Objects.requireNonNull(session.getType(TYPE_NAME), "type not created: " + TYPE_NAME);
}
}
private static void execQuery(final IDfSession session, final String dql) throws DfException {
OUT.println(dql);
new DfQuery(dql).execute(session, IDfQuery.DF_EXEC_QUERY).close();
}
}
class AllAttrsObjectQueryBuilder {
private static final String LF_CONTINUED = "\n ";
private static final int DQL_LINESZ = 110;
private final IDfType type;
private boolean hasRepeatings;
private final StringBuilder sb = new StringBuilder();
private final int initialLength;
public StringBuilder getSb() {
return sb;
}
public String getTypeName() throws DfException {
return type.getName();
}
AllAttrsObjectQueryBuilder(final IDfType type) throws DfException {
this.type = type;
beginBuild();
initialLength = sb.length();
}
private StringBuilder beginBuild() throws DfException {
sb.setLength(0);
sb.append("\n SELECT ");
appendAllAttrs();
sb.append(LF_CONTINUED);
sb.append("FROM ").append(type.getName()).append(LF_CONTINUED);
return sb;
}
public void resetLength() {
sb.setLength(initialLength);
}
public StringBuilder appendOrderBy() {
sb.append(" ORDER BY r_object_id");
if (hasRepeatings) {
sb.append(", i_position DESC");
}
return sb;
}
private void appendAllAttrs() throws DfException {
{
hasRepeatings = false;
for (int i = 0, n = type.getTypeAttrCount(); i < n; i++) {
final IDfAttr attr = type.getTypeAttr(i);
if (attr.isRepeating()) {
hasRepeatings = true;
}
a(sb, attr.getName());
a(sb, ",");
}
a(sb, DfDocbaseConstants.R_OBJECT_ID);
a(sb, ",");
a(sb, DfDocbaseConstants.I_VSTAMP);
if (hasRepeatings) {
a(sb, ',');
a(sb, "i_position");
}
}
}
private static void a(final StringBuilder buf, final Object o) {
final int nextBreak = buf.lastIndexOf("\n") + DQL_LINESZ + 1;
if (nextBreak <= buf.length()) {
buf.append(LF_CONTINUED);
}
buf.append(o);
}
}
Here's the program output:
deleting previously created objects
delete dm_sysobject objects where object_name = 'testchangetype'
newObject()
save()
change dm_sysobject objects to testchangetype where object_name = 'testchangetype'
SELECT object_name,r_object_type,title,subject,authors,keywords,a_application_type,a_status,r_creation_date,
r_modify_date,r_modifier,r_access_date,a_is_hidden,i_is_deleted,a_retention_date,a_archive,a_compound_architecture
,a_link_resolved,i_reference_cnt,i_has_folder,i_folder_id,r_composite_id,r_composite_label,r_component_label
,r_order_no,r_link_cnt,r_link_high_cnt,r_assembled_from_id,r_frzn_assembly_cnt,r_has_frzn_assembly,resolution_label
,r_is_virtual_doc,i_contents_id,a_content_type,r_page_cnt,r_content_size,a_full_text,a_storage_type,i_cabinet_id
,owner_name,owner_permit,group_name,group_permit,world_permit,i_antecedent_id,i_chronicle_id,i_latest_flag
,r_lock_owner,r_lock_date,r_lock_machine,log_entry,r_version_label,i_branch_cnt,i_direct_dsc,r_immutable_flag
,r_frozen_flag,r_has_events,acl_domain,acl_name,a_special_app,i_is_reference,r_creator_name,r_is_public,r_policy_id
,r_resume_state,r_current_state,r_alias_set_id,a_effective_date,a_expiration_date,a_publish_formats,a_effective_label
,a_effective_flag,a_category,language_code,a_is_template,a_controlling_app,r_full_content_size,a_extended_properties
,a_is_signed,a_last_review_date,i_retain_until,r_aspect_name,i_retainer_id,i_partition,i_is_replica,i_vstamp
,s,r_object_id,i_vstamp,i_position
FROM testchangetype
where object_name = 'testchangetype' ORDER BY r_object_id, i_position DESC
getObjectsByQuery()
s:
setString()
s: newval
save()
s:
Exception in thread "main" java.lang.RuntimeException: Expected: 'newval', got: ''
at com.sn.efx.tools.utility.tst.AaaTestChangeType.checkVal(AaaTestChangeType.java:188)
at com.sn.efx.tools.utility.tst.AaaTestChangeType.changeTypeAndUpdate(AaaTestChangeType.java:137)
at com.sn.efx.tools.utility.tst.AaaTestChangeType.main(AaaTestChangeType.java:85)