docs: public void startRecovery() throws Exception {
          if (tc.isEntryEnabled())
              Tr.entry(tc, "startRecovery");
  
          // Note that _recoverDBLogStarted is always false if we are logging to a filesystem.
          // If we are logging to an RDBMS, then we will start the TM which will spin off a thread
          // to perform recovery processing. Unfortunately, this latter thread, as part of
          // DataSource processing, will also attempt to start the TM as a result of registering
          // ResourceInfo. This flag guards against that eventuality.
          if (!_recoverDBLogStarted) {
              synchronized (this) {
                  TMHelper.setTMService(this);
  
                  // Initalize trace
                  Tr.reinitializeTracer();
  
                  // Test whether we are logging to an RDBMS
                  final ConfigurationProvider cp = ConfigurationProviderManager.getConfigurationProvider();
                  if (cp != null && cp.isSQLRecoveryLog()) {
                      _recoverDBLogStarted = true;
                      if (tc.isDebugEnabled())
                          Tr.debug(tc, "Tran Logging to an RDBMS set recoverDBLogStarted flag");
                  }
  
                  if (getState() != TMService.TMStates.INACTIVE && getState() != TMService.TMStates.STOPPED) {
                      if (tc.isEntryEnabled())
                          Tr.exit(tc, "start", "Already started");
                      return;
                  }
  
                  setResyncException(null);
                  _recLogService = new RecLogServiceImpl();
  
                  // Create the Recovery Director
                  _recoveryDirector = RecoveryDirectorFactory.createRecoveryDirector();
  
                  // For cloud support, retrieve recovery identity from the configuration if it is defined.
                  if (cp != null) {
                      _recoveryIdentity = cp.getRecoveryIdentity();
                      if (tc.isDebugEnabled())
                          Tr.debug(tc, "RecoveryIdentity is ", _recoveryIdentity);
                      _recoveryGroup = cp.getRecoveryGroup();
                      if (tc.isDebugEnabled())
                          Tr.debug(tc, "recoveryGroup is ", _recoveryGroup);
                  }
  
                  //Add this guard to ensure that we have sufficient config to drive recovery.
                  boolean allowRecovery = true;
                  if (cp == null) {
                      // A null ConfigurationProvider cannot be tolerated.
                      allowRecovery = false;
                      if (tc.isDebugEnabled())
                          Tr.debug(tc, "Configuration Provider is null");
                  } else {
                      String sName = cp.getServerName();
                      if (tc.isDebugEnabled())
                          Tr.debug(tc, "Retrieved server name " + sName);
                      if (sName == null || sName.isEmpty()) {
                          // An empty string serverName suggests that the Location Service was unavailable
                          allowRecovery = false;
                      }
                  }
  
                  if (!allowRecovery) {
                      try {
                          shutdown();
                      } catch (RuntimeException e) {
                          FFDCFilter.processException(e, "com.ibm.tx.jta.util.TxTMHelper.start", "279", this);
                      }
  
                      final Throwable se = new SystemException();
                      if (tc.isEntryEnabled())
                          Tr.exit(tc, "start", se);
                      throw (SystemException) se;
                  }
  
                  if (_recoveryIdentity != null && !_recoveryIdentity.isEmpty()) {
                      _recLogService.initialize(_recoveryIdentity);
                  } else {
                      String serverName = null;
                      if (cp != null) {
                          serverName = cp.getServerName();
                      }
                      _recLogService.initialize(serverName);
                  }
  
                  TxRecoveryAgentImpl txAgent = createRecoveryAgent(_recoveryDirector);
  
                  // For now I'll code such that the presence of a RecoveryIdentity attribute says that we are operating in the Cloud
                  if (_recoveryIdentity != null && !_recoveryIdentity.isEmpty()) {
                      _recLogService.setPeerRecoverySupported(true);
                      txAgent.setPeerRecoverySupported(true);
                      // Override the disable2PC property if it has been set
                      TransactionImpl.setDisable2PCDefault(false);
                      Tr.audit(tc, "WTRN0108I: Server with identity " + _recoveryIdentity + " is monitoring its peers for Transaction Peer Recovery");
                  }
  
                  //TODO: We don't currently use the recoveryGroup....but in due course we will, so retain this
                  // code snippet
                  if (_recoveryGroup != null && !_recoveryGroup.isEmpty()) {
                      txAgent.setRecoveryGroup(_recoveryGroup);
  
                      _recLogService.setRecoveryGroup(_recoveryGroup);
                  }
  
                  setRecoveryAgent(txAgent);
  
                  // Fake recovery only mode if we're to wait
                  RecoveryManager._waitForRecovery = _waitForRecovery;
  
                  // Kick off recovery
                  _recLogService.startRecovery(_recoveryLogFactory);
  
                  // Defect RTC 99071. Don't make the STATE transition until recovery has been fully
                  // initialised, after replay completion but before resync completion.
                  setState(TMService.TMStates.RECOVERING);
  
                  if (_waitForRecovery) {
                      if (tc.isDebugEnabled())
                          Tr.debug(tc, "Waiting for completion of asynchronous recovery");
                      _asyncRecoverySemaphore.waitEvent();
                      if (tc.isDebugEnabled())
                          Tr.debug(tc, "Asynchronous recovery is complete");
  
                      if (_resyncException != null) {
                          try {
                              shutdown();
                          } catch (RuntimeException e) {
                              FFDCFilter.processException(e, "com.ibm.tx.jta.util.TxTMHelper.start", "137", this);
                          }
  
                          final Throwable se = new SystemException().initCause(_resyncException);
                          if (tc.isEntryEnabled())
                              Tr.exit(tc, "start", se);
                          throw (SystemException) se;
                      }
                  } // eof if waitForRecovery
              } // eof synchronized block
          } // eof if !_recoverDBLogStarted
          else if (tc.isDebugEnabled())
              Tr.debug(tc, "Tran Logging to an RDBMS and START processing is in progress");
  
          if (tc.isEntryEnabled())
              Tr.exit(tc, "startRecovery");
      }