A rare but recurrent issue that customers sometimes encounter is to how to connect to each one of distinct repositories with the same name or same docbase id, or even both if one repository is a clone of the other one. The present connection resolution technique based on the dfc.properties file does not support this and only lets one connect to the first matching repository found. Well knowing this limitation, why were they created with the same name in the first place ? Just don’t and that pitfall is avoided. Actually however, this situation makes sense when the repositories are created by different teams, e.g. one TEST repository for each application in development, or developers’ personal repositories, maybe local on their laptops, or an application’s repository existing in different stages of its lifecycle, e.g. a PRODUCT_CATALOG repository in DEV, TUNI, INT, CTLQ, ACC, PROD, ARCHIVED, and maybe CLONE_1, CLONE_2, etc…
Now, at some point, a developer would need to access simultaneously, say, PRODUCT_CATALOG in DEV and PRODUCT_CATALOG in PROD in order to troubleshoot a problem, a plausible scenario. Another scenario is when a common, DFCs-based service must access docbases with the same name coming from different, independently managed applications. So, how to do that ?

Yes, how to do that ?

In this article, I presented a possible solution based on editing the dfc.properties file on-the-fly prior to connecting, so its docbroker_host and docbroker_port parameters would point to the target repository’s docbroker. As you know, that file is required to be able to connect to repositories. It is read by the DFCs when a connection request is done from a DFCs client, and the docbrokers listed in there are queried in turn until one of them replies with the information for the requested target that projects to it.
The problem with this algorithm is that it is not selective enough to tell apart distinct repositories with the same name. If the target could be specified like docbase[.server_instance][@machine[:port]], that could work. Actually, the above syntax, minus the [:port] part, is accepted but it does not work in our case. A typical returned error is:

DfNoServersException:: THREAD: main; MSG: [DM_DOCBROKER_E_NO_SERVERS_FOR_DOCBASE]error: "The DocBroker running on host (null:0) does not know of a server for the specified docbase ([email protected])"; ERRORCODE: 100; NEXT: null

The hack described in the aforementioned article consisted in removing all the docbroker_host and docbroker_port pairs of parameters and inserting the exact one that is used by the repository of interest, so any ambiguity is lifted. Prior to the next connection, the work-around is repeated for the new target.
Wrappers around the command-line tools iapi and idql, wiapi respectively widql, do just that.
It works quite well for these tools but what about java DFCs clients ? I guess we could subclass the session manager’s getSession() or write a wrapper that applies the same work-around transparently and that was my intention at first when a customer raised the issue but I decided to do give OpenText’s knowledge base another try, in case an out of-the-box yet unknown parameter would solve this question with no programming needed, i.e. no customization of existing code. I was not left empty-handed as I found this article: “How can I dynamically switch between different Docbrokers using DFC?”, Article ID:KB8801087. Here is the full note:

How can I dynamically switch between different Docbrokers using DFC?

Article ID:KB8801087

Add FavoriteEmailNotifyPrint

Applies to

Documentum Foundation Classes 4.0

Summary

How can I dynamically switch between different Docbrokers using DFC?

Resolution
Normally, you are restricted to Docbases registered to theDocbroker specified in the DMCL.ini file. Modifying the apiConfigobject can still access Docbases that are not registered with thisDocbroker.

The steps involved are the following:
1.Get a session object for a docbase which is registered withthe docbroker specified in the dmcl.ini file.
2.Get an apiConfig object using the methodIDfSession.getClientConfig();
3.Set the 'primary_host" and "primary_port" attributes ofthis apiConfig object to a different docbroker.
4.Get a session for a different docbase registered with thisdocbroker.

For more details, please refer to the APIconfig object in theobject reference manual for Documentum 4i.
Legacy Article ID
ECD316940

It’s again a bit hacky and still requires a customization but at least it addresses the DFCs part. Although it is DFCs-oriented, as a proof of concept, let’s see first if we could make it work using the API from within iapi.

Testing from within iapi

In our test case, we have a docbase named dmtest73 with id 50000 projecting to docbroker host dmtest.cec on port 1489 and a different docbase with the same name dmtest73 but id 90005 projecting to the docbroker host docker on port 7489. Both docbrokers are present in the dfc.properties file. We want to be able to connect to each of those docbases. Let’s first try the normal, default connection:

$ iapi dmtest73 -Udmadmin -Pdmadmin
API> retrieve,c,dm_server_config
dump,c,l
USER ATTRIBUTES

  object_name                     : dmtest73
...
  owner_name                      : dmtest73
...
  acl_domain                      : dmtest73
...
  operator_name                   : dmtest73
...
  web_server_loc                  : dmtest.cec
...
SYSTEM ATTRIBUTES

  r_object_type                   : dm_server_config
  r_creation_date                 : 7/1/2019 19:26:18
  r_modify_date                   : 6/20/2021 23:55:33
...
  r_creator_name                  : dmtest73
...
  r_server_version                : 7.3.0000.0214  Linux64.Oracle
  r_host_name                     : dmtest.cec
  r_process_id                    : 908
  r_install_owner                 : dmadmin
...

# dump the docbase config too;
API> retrieve,s0,dm_docbase_config    
...
3c00c35080000103
API> dump,c,l
...
USER ATTRIBUTES

  object_name                     : dmtest73
  title                           : a v7.3 test repository
...
  owner_name                      : dmtest73
...
  acl_domain                      : dmtest73
...
  index_store                     : DM_DMTEST73_INDEX
...

SYSTEM ATTRIBUTES

  r_object_type                   : dm_docbase_config
  r_creation_date                 : 7/1/2019 19:26:18
  r_modify_date                   : 7/1/2019 17:33:50
...
  r_creator_name                  : dmtest73
...
  r_dbms_name                     : Oracle
  r_docbase_id                    : 50000
# we are in the docbase with id 50000;

So, this is the dmtest73 docbase that is accessed with the current docbroker definitions in dfc.properties.
Usually, only that docbase, with FQN [email protected]:1489, is reachable because its docbroker is listed earlier than dmtest73@docker:7489 in dfc.properties, as reported by the session’s apiconfig object:

dump,c,apiconfig
...
  dfc.docbroker.exclude.failure_th: 3
  dfc.docbroker.exclusion.time    : 30
  dfc.docbroker.host           [0]: dmtest.cec
                               [1]: dmtest.cec
                               [2]: docker
                               [3]: docker
                               [4]: docker
                               [5]: docker
  dfc.docbroker.port           [0]: 7289
                               [1]: 1489
                               [2]: 1489
                               [3]: 1589
                               [4]: 7489
                               [5]: 6489
  dfc.docbroker.protocol       [0]: rpc_static
                               [1]: rpc_static
                               [2]: rpc_static
                               [3]: rpc_static
                               [4]: rpc_static
                               [5]: rpc_static
  dfc.docbroker.search_order      : sequential
  dfc.docbroker.service        [0]: dmdocbroker
                               [1]: dmdocbroker
                               [2]: dmdocbroker
                               [3]: dmdocbroker
                               [4]: dmdocbroker
                               [5]: dmdocbroker
  dfc.docbroker.timeout        [0]: 0
                               [1]: 0
                               [2]: 0
                               [3]: 0
                               [4]: 0
                               [5]: 0
...

Here, 6 pairs of docbroker_host/docbroker_port were defined in the dfc.properties; each one has additional default parameters dfc.docbroker.protocol, dfc.docbroker.service and dfc.docbroker.timeout; they are all synchronized, i.e.
dfc.docbroker.host[i] uses port dfc.docbroker.port[i], dfc.docbroker.protocol[i], dfc.docbroker.service[i] with a timeout of dfc.docbroker.timeout[i].
The Note says to force the primary docbroker (i.e. the first one, corresponding to the values at index 0 of the dfc.docbroker% attributes) to the target docbase’s one; it doesn’t say anything about the other ones but we’ll remove them to eradicate any possibility of a fail over logic:

# empty the dfc.docbroker% attributes;
API> truncate,c,apiconfig,dfc.docbroker.host
truncate,c,apiconfig,dfc.docbroker.port
truncate,c,apiconfig,dfc.docbroker.protocol
truncate,c,apiconfig,dfc.docbroker.service
truncate,c,apiconfig,dfc.docbroker.timeout

# add the target docbase's docbroker;
API> append,c,apiconfig,dfc.docbroker.host
docker
append,c,apiconfig,dfc.docbroker.port
7489
append,c,apiconfig,dfc.docbroker.protocol
rpc_static
append,c,apiconfig,dfc.docbroker.service
dmdocbroker
append,c,apiconfig,dfc.docbroker.timeout
0

# verify the parameters;
API> dump,c,apiconfig
...
  dfc.docbroker.host           [0]: docker
  dfc.docbroker.port           [0]: 7489
  dfc.docbroker.protocol       [0]: rpc_static
  dfc.docbroker.search_order      : sequential
  dfc.docbroker.service        [0]: dmdocbroker
  dfc.docbroker.timeout        [0]: 0
...

# try to connect to dmtest73@docker:7489 now; 
API> connect,dmtest73,dmadmin,dmadmin
...
s1
# OK but where are we really ?
API> retrieve,s1,dm_server_config
...
3d015f9580000102
API> dump,c,l
USER ATTRIBUTES

  object_name                     : dmtest73
...
  owner_name                      : dmtest73c
...
  acl_domain                      : dmtest73c
...
  operator_name                   : dmtest73c
...
  web_server_loc                  : container73

SYSTEM ATTRIBUTES

  r_object_type                   : dm_server_config
  r_creation_date                 : 6/20/2021 02:52:36
  r_modify_date                   : 6/20/2021 00:59:43
...
  r_creator_name                  : dmtest73c
...
  r_server_version                : 16.4.0000.0248  Linux64.Oracle
  r_host_name                     : container73
  r_process_id                    : 13709
...

# dump the docbase config too;
API> retrieve,s1,dm_docbase_config
...
3c015f9580000103
API> dump,c,l
...
USER ATTRIBUTES

  object_name                     : dmtest73
  title                           : dmtest73 homonym silently
...
...
  acl_domain                      : dmtest73c
...
  index_store                     : dm_dmtest73c_index
...

SYSTEM ATTRIBUTES

  r_object_type                   : dm_docbase_config
  r_creation_date                 : 6/20/2021 02:52:36
  r_modify_date                   : 6/20/2021 01:27:22
...
...
  r_dbms_name                     : Oracle
  r_docbase_id                    : 90005
...
# we are now in the docbase with id 90005;

It works as proved by comparing the dm_server_config and dm_docbase_config objects, notably the dm_docbase_config.r_docbase_id.
So, what to think of such a solution ? It requires some cutting and pasting of statements but they could be saved into some sort of macros depending on the command-line client used (e.g. the GUI-based dqman). For iapi I’d definitively prefer starting it as described in the above article, e.g.

$ wiapi dmtest73:docker:7289
$ widql dmtest73:dmtest.cec:1489

but if several connections to homonym docbases must be opened at once in the same iapi working session, this is the only way.

The DFCs version

The solution from the Note:KB8801087 was for the DFCs in the first place. Let’s apply it in function getSessionExtended() (starting on line 46 in the listing below) with the following profile:

public void getSessionExtended(String repo, String user, String passwd) throws Exception

The function takes a docbase’s specification in repo, and a user name and password to connect to the repository. As we need a unambiguous syntax to define repo, let’s use the time proven one:

docbase_name[:docbroker_machine[:docbroker_port]]

where docbroker_machine:docbroker_port are the coordinates of the docbroker, possibly remote, the docbase docbase_name projects to. Obviously, two homonym docbases cannot project to the same docbroker (the docbroker would reject them all but the first one), but they could be running on the same machine and project to distinct docbrokers, locally or remotely.
An alternate syntax could be:

docbase_name@docbroker_machine:docbroker_port

If preferred, the change is easy in the function’s regular expression (see line 51 below):

Pattern re_docbase_docbroker_host_docbroker_port = Pattern.compile("^([^:]+)(@([^:]+)(:([^:]+))?)?$");

The function will first parse the extended repository syntax (starting on line 53), apply the Note’s hack (lines 81 to 87), and finally connect (line 96). To be sure we are in the right docbase, all the configuration objects will be dumped by the ancillary function dump_current_configs() (defined starting on line 124, called on line 182) as well. Starting on line 111, the apiconfig object is displayed to check the hack’s change. On lines 102 to 108, we find out the minimum field width to display the apiconfig’s attributes without truncation, as the dump() method does a lame job here.
If no docbroker is specified, then the function fails back to the DFCs default behavior so it remains backwards compatible.
In order to make the test possible, a main() function (starting on line 157) accepting and parsing command-line parameters (starting on line 167) is also provided.

// A test program for function getSessionExtended() to open sessions using an extended syntax;
// June 2021, [email protected];
// to compile: javac extendedConnection.java
// to execute: java -classpath .:$DOCUMENTUM/config:$CLASSPATH extendedConnection target_docbase user_name password
// the programm will attempt to connect to target_docbase using those credentials;
// target_docbase's syntax is:
//   docbase_name[:docbroker_machine[:docbroker_port]]
// if docbroker_machine is missing (and hence docbroker_port too), a session is opened through the default behavior from the dfc.properties file, i.e. following the order the docbrokers are listed in that file;
// otherwise, the docbrokers listed in dfc.properties are not used and the specified docbroker is;
// so the function is compatible with the default behavior of the DFCs;
import com.documentum.fc.client.IDfClient;
import com.documentum.fc.client.DfClient;
import com.documentum.fc.client.DfQuery;
import com.documentum.fc.client.IDfCollection;
import com.documentum.fc.client.IDfDocbaseMap;
import com.documentum.fc.client.IDfQuery;
import com.documentum.fc.client.IDfSession;
import com.documentum.fc.client.IDfSessionManager;
import com.documentum.fc.common.DfLoginInfo;
import com.documentum.fc.common.IDfLoginInfo;
import com.documentum.fc.common.IDfAttr;
import com.documentum.fc.client.IDfTypedObject;
import com.documentum.fc.client.IDfPersistentObject;
import java.io.RandomAccessFile;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.Enumeration;

public class extendedConnection {
   String gr_username = null;
   String gr_password = null;
   IDfSessionManager sessMgr = null;
   IDfSession idfSession;
 
   public void usage() {
   // output the utility extended repository's syntax;
      System.out.println("Usage:");
      System.out.println("   java [-Ddfc.properties.file=/tmp/dfc.properties] -classpath .:/app/dctm/config:$CLASSPATH docbase[:docbroker-host[:docbroker-port]] username password");
      System.out.println("Use the extended repository syntax (e.g. dmtest:docker:7289, vs. dmtest) to override the DFCs' default resolution mechanism.");
      System.out.println("Examples:");
      System.out.println("   java -classpath .:/app/dctm/config:$CLASSPATH dctmping dmtest73 dmadmin dmadmin");
      System.out.println("for using the docbrokers defined in the dfc.properties (classic usage)");
      System.out.println("   java -classpath .:/tmp:$CLASSPATH dctmping dmtest73:docker:7489 dmadmin dmadmin");
      System.out.println("for short-circuiting the docbrokers and using the repo's extended syntax");
   }
   public void getSessionExtended(String repo, String user, String passwd) throws Exception {
   // change the dfc.docbroker.host and dfc.docbroker.port to connect with more flexibility;
   // The target repository repo is defined though the following advanced syntax:
   //    docbase[:docbroker-host[:docbroker-port]]
      System.out.printf("getSessionExtended%n");
      Pattern re_docbase_docbroker_host_docbroker_port = Pattern.compile("^([^:]+)(:([^:]+)(:([^:]+))?)?$");

      Matcher check = re_docbase_docbroker_host_docbroker_port.matcher(repo);
      String docbase = null;
      String docbroker_host = null;
      String docbroker_port = null;
      if (check.find()) {
         docbase = check.group(1);
         docbroker_host = check.group(3);
         docbroker_port = check.group(5);
      } 
      else {
         System.out.println("Missing docbase name; the docbase is mandatory");
         usage();
      }
      if (docbroker_host != null) {
         System.out.println("host = " + docbroker_host);
         if (docbroker_port == null)
            docbroker_port = "1489";
         System.out.println("port = " + docbroker_port);
      } 
      else
         System.out.println("docbroker host is empty, using the dfc.properties");
      System.out.println("using the " + (docbroker_host != null ? (" docbroker host " + docbroker_host + ":" + docbroker_port) : "the dfc.properties"));

      IDfClient client = DfClient.getLocalClient();
      IDfTypedObject client_config = client.getClientConfig();

      if (docbroker_host != null) {
         // let's hack the session config to force the given docbroker[:port];
         client_config.truncate("dfc.docbroker.host", 0);
         client_config.appendString("dfc.docbroker.host", docbroker_host);
         client_config.truncate("dfc.docbroker.port", 0);
         client_config.appendString("dfc.docbroker.port", docbroker_port);
         client_config.truncate("dfc.docbroker.protocol", 1);
         client_config.truncate("dfc.docbroker.service", 1);
         client_config.truncate("dfc.docbroker.timeout", 1);
      }

      IDfLoginInfo login = new DfLoginInfo();
      login.setUser(user);
      login.setPassword(passwd);
      // as recommended, use the session manager;
      sessMgr = client.newSessionManager();
      sessMgr.setIdentity(docbase, login);
      idfSession = sessMgr.getSession(docbase);

      System.out.printf("session config:%n");
      int max_length = 0;
      // as the default presentation from dump() sucks too much due to the truncated attribut names, let's produce a non-truncated one:
      // first, iterate through the session config and find the longest one;
      for (Enumeration e = client_config.enumAttrs(); e.hasMoreElements() ;) {
         IDfAttr attr = (IDfAttr) e.nextElement();
         String name = attr.getName();
         String value = client_config.getString(name);
         if (null != value)
            max_length = max_length >= name.length() ? max_length : name.length();
      }
      // max_length contains now the length of the longest attribute name;
      // display the nicely formatted session config;
      for (Enumeration e = client_config.enumAttrs(); e.hasMoreElements() ;) {
         IDfAttr attr = (IDfAttr) e.nextElement();
         String name = attr.getName();
         String value = client_config.getAllRepeatingStrings(name, "n" + String.join("", new String(new char[max_length]).replace("", " ") + "  "));
         System.out.printf("%" + max_length + "s: %s%n", name, value);
      }
   }
 
   public void releaseSession() throws Exception {
   // quite obvious;
      sessMgr.release(idfSession);
   }
 
   public void dump_all_configs() throws Exception {
   // dump all the server and docbase configs defined in repository;
      System.out.printf("%nin dump_all_configs%n");
      String[] configs = {"select r_object_id from dm_server_config",
                          "select r_object_id from dm_docbase_config"};
      IDfQuery query = new DfQuery();
      for (String dql_stmt: configs) {
         System.out.println("executing " + dql_stmt);
         query.setDQL(dql_stmt);
         IDfCollection collection = null;
         String r_object_id = null;
         try {
            collection = query.execute(idfSession, IDfQuery.DF_READ_QUERY);
            while (collection.next()) {
               r_object_id = collection.getString("r_object_id");
               IDfPersistentObject obj = idfSession.getObjectByQualification("dm_sysobject where r_object_id = '" + r_object_id + "'");
               System.out.println("dumping object with id = " + r_object_id);
               System.out.println(obj.dump());
            }
         }
         catch(Exception e) {
            System.out.printf("Error in dumps_all_configs()%n");
            System.out.println(e.getMessage());
            e.printStackTrace();
            // continue as far as possible;
         }
         finally {
            if (collection != null)
               collection.close();
         }
      }
   }

   public static void main(String[] args) throws Exception {
      System.out.printf("%nextendedConnection started ...%n");
      extendedConnection dmtest = new extendedConnection();
      if (0 == args.length)
         System.exit(0);

      String docbase = null;
      String user    = null;
      String passwd  = null;
      // if any arguments are present, they must be the target docbase and the credentials to connect (username and password);
      if (args.length != 3) {
         System.out.println("Missing arguments. Usage: dctmping [target_docbase [user_name password]]");
         System.exit(1);
      }
      else {
         docbase = args[0];
         user    = args[1];
         passwd  = args[2];
      }

      try {
         // connect using the command-line parameters;
         dmtest.getSessionExtended(docbase, user, passwd);

         //dump all the server and docbase configs;
         dmtest.dump_all_configs();
      }
      catch(Exception e) {
         System.out.printf("Error while working in the docbase %s as user %sn", docbase, user);
         System.out.println(e.getMessage());
         e.printStackTrace();
      }
      finally {
         try {
            dmtest.releaseSession();
         }
         catch(Exception e) {}
      }
   }
}

Interestingly, the DFCs’ truncate method has an additional argument compared to its API’s equivalent, the index at which truncation should start. Also, using the DFCs, no opened session is needed prior to accessing the config temporary object, named here client config vs. API’s apiconfig.
Save this code into a file named extendedConnection.java in current directory.
To compile it:

javac extendedConnection.java

To execute it from current directory (paths may vary according to your installation):

export DOCUMENTUM=/app/dctm
export CLASSPATH=$DOCUMENTUM/dctm.jar:$DOCUMENTUM/dfc/dfc.jar
$ java -classpath .:$DOCUMENTUM/config:$CLASSPATH extendedConnection docbase username password

Example of output

Here is an example of the default behavior, i.e. when the target repo does not use the extended syntax repo:docbroker_host[:docbroker_port]:

$ java -classpath .:/app/dctm/config:$CLASSPATH extendedConnection dmtest73 dmadmin dmadmin

extendedConnection started ...
getSessionExtended
docbroker host is empty, using the dfc.properties
using the the dfc.properties
session config:
                                                  dfc.name: dfc
                                            dfc.config.dir: /app/dctm/config
                                           dfc.config.file: file:/app/dctm/config/dfc.properties
...
                                        dfc.docbroker.host: 
                                                            192.168.56.12
                                                            
                                                            192.168.56.15
                                                            192.168.56.15
                                                            192.168.56.15
                                        dfc.docbroker.port: 0
                                                            1489
                                                            0
                                                            7489
                                                            6489
                                                            1489
...
                                    dfc.docbroker.protocol: rpc_static
                                                            rpc_static
                                                            rpc_static
                                                            rpc_static
                                                            rpc_static
                                                            rpc_static
                                     dfc.docbroker.service: dmdocbroker
                                                            dmdocbroker
                                                            dmdocbroker
                                                            dmdocbroker
                                                            dmdocbroker
                                                            dmdocbroker
                                     dfc.docbroker.timeout: 0
                                                            0
                                                            0
                                                            0
                                                            0
                                                            0
...

in dump_all_configs
executing select r_object_id from dm_server_config
dumping object with id = 3d00c35080000102
USER ATTRIBUTES

  object_name                     : dmtest73
  title                           : 
  subject                         : 
...
  owner_name                      : dmtest73
...

SYSTEM ATTRIBUTES

  r_object_type                   : dm_server_config
  r_creation_date                 : 7/1/2019 7:26:18 PM
...
  r_creator_name                  : dmtest73
...
  r_server_version                : 7.3.0000.0214  Linux64.Oracle
  r_host_name                     : dmtest.cec
...

executing select r_object_id from dm_docbase_config
dumping object with id = 3c00c35080000103
USER ATTRIBUTES

  object_name                     : dmtest73
  title                           : a v7.3 test repository
...
  acl_domain                      : dmtest73
...
  index_store                     : DM_DMTEST73_INDEX
...

SYSTEM ATTRIBUTES

  r_object_type                   : dm_docbase_config
  r_creation_date                 : 7/1/2019 7:26:18 PM
...
  r_creator_name                  : dmtest73
...
  r_docbase_id                    : 50000
...

This is the dmtest73 docbase with id 50000, like in the iapi example seen before.
Make sure $CLASSPATH includes the dfc.jar, or dctm.jar if going through the manifest in it is preferred.
Next, an example of accessing a docbase with the same name as previously but on another host, using the extended syntax:

$ java -classpath .:/app/dctm/config:$CLASSPATH extendedConnection dmtest73:docker:7489 dmadmin dmadmin

extendedConnection started ...
getSessionExtended
host = docker
port = 7489
using the  docbroker host docker:7489
session config:
                                                  dfc.name: dfc
                                            dfc.config.dir: /app/dctm/config
                                           dfc.config.file: file:/app/dctm/config/dfc.properties
...
                                        dfc.docbroker.host: docker
                                        dfc.docbroker.port: 7489
...
                                    dfc.docbroker.protocol: rpc_static
                                     dfc.docbroker.service: dmdocbroker
                                     dfc.docbroker.timeout: 0
...

in dump_all_configs
executing select r_object_id from dm_server_config
dumping object with id = 3d015f9580000102
USER ATTRIBUTES

  object_name                     : dmtest73
  title                           : 
  subject                         : 
...

SYSTEM ATTRIBUTES

  r_object_type                   : dm_server_config
  r_creation_date                 : 6/20/2021 2:52:36 AM
...
  r_creator_name                  : dmtest73c
...
  r_server_version                : 16.4.0000.0248  Linux64.Oracle
  r_host_name                     : container73
...

executing select r_object_id from dm_docbase_config
dumping object with id = 3c015f9580000103
USER ATTRIBUTES

  object_name                     : dmtest73
  title                           : dmtest73 homonym silently
...
  acl_domain                      : dmtest73c
...
  index_store                     : dm_dmtest73c_index
...

SYSTEM ATTRIBUTES

  r_object_type                   : dm_docbase_config
  r_creation_date                 : 6/20/2021 2:52:36 AM
...
  r_creator_name                  : dmtest73c
...
  r_docbase_id                    : 90005
...

The reached docbase has the 90005, as expected.
As a final example, let’s connect to the default dmtest73 again but this time using the extended syntax:

$ java -classpath .:/app/dctm/config:$CLASSPATH dctmping dmtest73:dmtest.cec:1489 dmadmin dmadmin

extendedConnection started ...

getSessionExtended
host = dmtest.cec
port = 1489
using the  docbroker host dmtest.cec:1489
session config:
                                                  dfc.name: dfc
                                            dfc.config.dir: /app/dctm/config
                                           dfc.config.file: file:/app/dctm/config/dfc.properties
...
                                  dfc.docbroker.debug.host: 
                                  dfc.docbroker.debug.port: 0
..
                                        dfc.docbroker.host: dmtest.cec
                                        dfc.docbroker.port: 1489
..
                                    dfc.docbroker.protocol: rpc_static
                                     dfc.docbroker.service: dmdocbroker
                                     dfc.docbroker.timeout: 0
...

in dump_all_configs
executing select r_object_id from dm_server_config
dumping object with id = 3d00c35080000102
USER ATTRIBUTES

  object_name                     : dmtest73
  title                           : 
  subject                         : 
...
  operator_name                   : dmtest73
...
  web_server_loc                  : dmtest.cec
...

SYSTEM ATTRIBUTES

  r_object_type                   : dm_server_config
  r_creation_date                 : 7/1/2019 7:26:18 PM
...
  r_creator_name                  : dmtest73
...
  r_server_version                : 7.3.0000.0214  Linux64.Oracle
  r_host_name                     : dmtest.cec
...

executing select r_object_id from dm_docbase_config
dumping object with id = 3c00c35080000103
USER ATTRIBUTES

  object_name                     : dmtest73
  title                           : a v7.3 test repository
...
  acl_domain                      : dmtest73
...
  index_store                     : DM_DMTEST73_INDEX
...

SYSTEM ATTRIBUTES

  r_object_type                   : dm_docbase_config
  r_creation_date                 : 7/1/2019 7:26:18 PM
...
  r_creator_name                  : dmtest73
...
  r_docbase_id                    : 50000
...

The reached docbase has id 50000 as expected.
The client config shows here the same output as sessionconfig from within iapi, which shouldn’t come as a surprise given that iapi invokes the DFCs behind the scenes.
As with the alternative in the aforementionned article, this work-around even allows to completely remove the docbroker_host/docbroker_port pairs from the dfc.properties file as it does not use them and imposes its own direct, flattened resolution mechanism (“just contact the damn given docbroker”). This can be verified with a stripped-down dfc.properties file (e.g. /tmp/dfc.properties) with no such entries and invoking the test program thusly:

$ java -Ddfc.properties.file=/tmp/dfc.properties -classpath .:$CLASSPATH extendedConnection dmtest73:docker:7489 dmadmin dmadmin

Of course, in such a case, the default resolution mechanism won’t work if attempted to be used through the normal repository syntax, and the DFCs will complain with an error as shown below:

$ java -Ddfc.properties.file=/tmp/dfc.properties -classpath .:$CLASSPATH extendedConnection dmtest73 dmadmin dmadmin

extendedConnection started ...
getSessionExtended
docbroker host is empty, using the dfc.properties
using the the dfc.properties
Error while working in the docbase dmtest73 as user dmadmin
[DM_DOCBROKER_E_NO_DOCBROKERS]error:  "No DocBrokers are configured"
DfServiceException:: THREAD: main; MSG: [DM_DOCBROKER_E_NO_DOCBROKERS]error:  "No DocBrokers are configured"; ERRORCODE: 100; NEXT: null
	at com.documentum.fc.client.DfServiceException.newNoDocbrokersException(DfServiceException.java:44)
...

Conclusion

Although this work-around smells like a hack, it is a very effective one. From within iapi or any DFCs client with a slightly smarter connection function, this recurrent yet pesky limitation has finally found a solution. However, while it is acceptable for in-house development where source code is available, third-party developers might not want to bother with an ad hoc customization to fix a niche problem; so some per$ua$ion work might be needed here too. Let’s hope that OpenText, in breaking with a 30 years-old code immobilism in this area, will delight us soon with a really transparent solution which, who knows, supports an enhanced repository syntax such as the proposed one.