docs: @Override
      public synchronized RecoveryLog getRecoveryLog(FailureScope failureScope, LogProperties logProperties) throws InvalidLogPropertiesException {
          if (tc.isEntryEnabled())
              Tr.entry(tc, "getRecoveryLog", new java.lang.Object[] { failureScope, logProperties, this });
          /* 5@PK01151D */
          // If we're on Z, we can have a ZLogProperties (System Logger) based
          // recovery log.  Otherwise, FileLogProperties and CustomLogProperties are the only supported types.
          if (logProperties instanceof StreamLogProperties) {
              // final PlatformHelper ph = PlatformHelperFactory.getPlatformHelper();
              // if (ph.isZOS() == false)
              if (Configuration.isZOS() == false) {
                  if (tc.isEventEnabled())
                      Tr.event(tc, "Unable to create stream based recovery log on non-ZOS platform"); /* @LIDB2561.1A */
                  if (tc.isEntryEnabled())
                      Tr.exit(tc, "getRecoveryLog");
                  throw new InvalidLogPropertiesException();
              }
          } else if (!(logProperties instanceof FileLogProperties || logProperties instanceof CustomLogProperties)) {
              if (tc.isEventEnabled())
                  Tr.event(tc, "Unable to create non-file based or non-Custom recovery log");
              if (tc.isEntryEnabled())
                  Tr.exit(tc, "getRecoveryLog");
              throw new InvalidLogPropertiesException();
          }
  
          final Integer logIdentifier = new Integer(logProperties.logIdentifier());
  
          RecoveryLog recoveryLog = null;
  
          // Extract all of the logs that are currently available for the given log
          // identifier.
          HashMap logsByFailureScope = (HashMap) _recoveryLogs.get(logIdentifier);
  
          if (logsByFailureScope != null) {
              // One or more logs for the given identifier is already available.
              // See if any of these logs are for the given failure scope.
              recoveryLog = (RecoveryLog) logsByFailureScope.get(failureScope);
          } else {
              // There were no logs for the given identifier. Initialize the
              // hashmap for this identifier and add it to the outer map so
              // that it can be used to store the log that will be created
              // below.
              logsByFailureScope = new HashMap();
              _recoveryLogs.put(logIdentifier, logsByFailureScope);
          }
  
          if (recoveryLog == null) {
              if (logProperties instanceof FileLogProperties) {
                  // The requested log has not been accessed already so we must create it.
                  MultiScopeLog multiScopeRecoveryLog = null;
                  HashMap multiScopeLogsByServerName = null; /* @253893A */
                  String serverName = failureScope.serverName(); /* @253893A */
  
                  final FileLogProperties fileLogProperties = (FileLogProperties) logProperties;
  
                  // File-based recovery logs have two different types. A multiple
                  // scope log type indicates that records for more than one failure
                  // scope may be stored in the same log. A single scope log type
                  // indicates that records for different failure scopes must be
                  // stored in different logs.
                  final int logType = fileLogProperties.logType();
  
                  if (logType == FileLogProperties.LOG_TYPE_MULTIPLE_SCOPE) {
                      // If this is a multiple scope log then we can check to see if
                      // we have an existing log for the given identifier. If we do
                      // we can re-use it.  A multi-scope log will only contain failure
                      // scopes that share a server name.  In an HA-enabled environment
                      // it's possible for a log identifier to have more than one
                      // log.
                      multiScopeLogsByServerName = (HashMap) _multiScopeRecoveryLogs.get(logIdentifier); /* @253893C */
  
                      if (multiScopeLogsByServerName != null) /* @253893A */
                      { /* @253893A */
                          multiScopeRecoveryLog = (MultiScopeLog) multiScopeLogsByServerName.get(serverName); /* @253893A */
                      } /* @253893A */
                      else /* @253893A */
                      { /* @253893A */
                          multiScopeLogsByServerName = new HashMap(); /* @253893A */
                          _multiScopeRecoveryLogs.put(logIdentifier, multiScopeLogsByServerName); /* @253893A */
                      } /* @253893A */
                  }
  
                  if (multiScopeRecoveryLog == null) {
                      // Either a single scope log is required or there was no
                      // existing log for the given identifier. Create a new log.
                      multiScopeRecoveryLog = new MultiScopeRecoveryLog(fileLogProperties, _recoveryAgent, failureScope);
  
                      if (logType == FileLogProperties.LOG_TYPE_MULTIPLE_SCOPE) {
                          // If this is a multiple scope log then we store it in the map so
                          // that it can be re-used by subsequent requests for a log with the
                          // same log identifier.
                          //
                          // It is worth noting that in an environment where the only logs
                          // created are single scope logs this map will
                          // remain empty.
                          multiScopeLogsByServerName.put(serverName, multiScopeRecoveryLog); /* @253893A */
                      }
                  }
  
                  // Create a new RecoveryLog object to be returned to the caller and
                  // store it in the map so that it can be re-used if necessary.
                  recoveryLog = new RecoveryLogImpl(multiScopeRecoveryLog, failureScope);
              } else if (logProperties instanceof CustomLogProperties) {
                  // The requested log has not been accessed already so we must create it.
                  MultiScopeLog multiScopeRecoveryLog = null;
                  HashMap multiScopeLogsByServerName = null; /* @253893A */
                  String serverName = failureScope.serverName(); /* @253893A */
  
                  final CustomLogProperties customLogProperties = (CustomLogProperties) logProperties;
  
                  // Custom recovery logs have two different types. A multiple
                  // scope log type indicates that records for more than one failure
                  // scope may be stored in the same log. A single scope log type
                  // indicates that records for different failure scopes must be
                  // stored in different logs.
                  final int logType = customLogProperties.logType();
  
                  if (logType == CustomLogProperties.LOG_TYPE_MULTIPLE_SCOPE) {
                      // If this is a multiple scope log then we can check to see if
                      // we have an existing log for the given identifier. If we do
                      // we can re-use it.  A multi-scope log will only contain failure
                      // scopes that share a server name.  In an HA-enabled environment
                      // it's possible for a log identifier to have more than one
                      // log.
                      multiScopeLogsByServerName = (HashMap) _multiScopeRecoveryLogs.get(logIdentifier); /* @253893C */
  
                      if (multiScopeLogsByServerName != null) /* @253893A */
                      { /* @253893A */
                          multiScopeRecoveryLog = (MultiScopeLog) multiScopeLogsByServerName.get(serverName); /* @253893A */
                      } /* @253893A */
                      else /* @253893A */
                      { /* @253893A */
                          multiScopeLogsByServerName = new HashMap(); /* @253893A */
                          _multiScopeRecoveryLogs.put(logIdentifier, multiScopeLogsByServerName); /* @253893A */
                      } /* @253893A */
                  }
  
                  if (multiScopeRecoveryLog == null) {
                      // Either a single scope log is required or there was no
                      // existing log for the given identifier. Create a new log.
  
                      // Need to locate the factory for this Custom log via RecoveryDirector
                      // then create a log ... this could be a single or multiple scope log at this point
                      // check the type of returned log and if necessary wrap in a RecoveryLogImpl
                      final String customLogId = customLogProperties.pluginId();
                      if (tc.isDebugEnabled())
                          Tr.debug(tc, "Look in properties with customLogId, " + customLogId);
                      RecoveryLogFactory factory = _customLogFactories.get(customLogId);
                      if (tc.isDebugEnabled())
                          Tr.debug(tc, "Retrieved factory, " + factory);
  
                      if (factory == null) {
                          if (tc.isEventEnabled())
                              Tr.event(tc, "Custom recovery log factory NOT FOUND for ", customLogId);
  
                          if (tc.isEntryEnabled())
                              Tr.exit(tc, "getRecoveryLog");
                          throw new InvalidLogPropertiesException();
                      }
  
                      recoveryLog = factory.createRecoveryLog(customLogProperties, _recoveryAgent, Configuration.getRecoveryLogComponent(), failureScope);
                      if (recoveryLog == null) {
                          if (tc.isEventEnabled())
                              Tr.event(tc, "Custom recovery log factory returned NULL recovery log", customLogId);
                          if (tc.isEntryEnabled())
                              Tr.exit(tc, "getRecoveryLog");
                          throw new InvalidLogPropertiesException();
                      }
  
                      if (logType == CustomLogProperties.LOG_TYPE_MULTIPLE_SCOPE && recoveryLog instanceof MultiScopeLog) {
                          // If this is a multiple scope log then we store it in the map so
                          // that it can be re-used by subsequent requests for a log with the
                          // same log identifier.
                          //
                          // It is worth noting that in an environment where the only logs
                          // created are single scope logs this map will
                          // remain empty.
                          multiScopeRecoveryLog = (MultiScopeLog) recoveryLog;
                          multiScopeLogsByServerName.put(serverName, multiScopeRecoveryLog); /* @253893A */
  
                          recoveryLog = new RecoveryLogImpl(multiScopeRecoveryLog, failureScope);
                      }
                  } else {
                      // Create a new RecoveryLog object to be returned to the caller and
                      // store it in the map so that it can be re-used if necessary.
                      recoveryLog = new RecoveryLogImpl(multiScopeRecoveryLog, failureScope);
                  }
              } else {
                  // This is a stream log properties object so create
                  // the z-specific log - use reflection to do this
                  // to avoid a compile and runtime dependency on
                  // the z-specific code.
                  // TDK - IXGRecoveryLogImpl is in the same component....
                  try {
                      final Constructor ixgLogConstructor = Class.forName("com.ibm.ws390.recoverylog.spi.IXGRecoveryLogImpl").getConstructor(new Class[] {
                                                                                                                                                           com.ibm.ws.recoverylog.spi.FailureScope.class,
                                                                                                                                                           com.ibm.ws.recoverylog.spi.StreamLogProperties.class,
                                                                                                                                                           com.ibm.ws.recoverylog.spi.RecoveryAgent.class });
                      recoveryLog = (RecoveryLog) ixgLogConstructor.newInstance(new Object[] { failureScope, (StreamLogProperties) logProperties, _recoveryAgent });
                  } catch (Exception e) {
                      FFDCFilter.processException(e, "com.ibm.ws.recoverylog.spi.RecoveryLogManagerImpl.getRecoveryLog", "278", this);
                      if (tc.isEventEnabled())
                          Tr.event(tc, "Exception caught initializing stream-based log", e);
                      if (tc.isEntryEnabled())
                          Tr.exit(tc, "getRecoveryLog", "InvalidLogPropertiesException");
                      throw new InvalidLogPropertiesException(e);
                  }
              }
  
              logsByFailureScope.put(failureScope, recoveryLog);
          }
  
          if (tc.isEntryEnabled())
              Tr.exit(tc, "getRecoveryLog", recoveryLog);
          return recoveryLog;
      }