static AthenaTransportLinkModule *
_LoadModule(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, const char *moduleName)
{
    PARCArrayList *newModuleList = NULL;

    // XXX need to dynamically load these, they're all hardwired for now
    if (strcasecmp(moduleName, "TCP") == 0) {
        newModuleList = athenaTransportLinkModuleTCP_Init();
    }
    if (strcasecmp(moduleName, "UDP") == 0) {
        newModuleList = athenaTransportLinkModuleUDP_Init();
    }
    if (strcasecmp(moduleName, "ETH") == 0) {
        newModuleList = athenaTransportLinkModuleETH_Init();
    }

    if (newModuleList) {
        for (int index = 0; index < parcArrayList_Size(newModuleList); index++) {
            AthenaTransportLinkModule *athenaTransportLinkModule = parcArrayList_Get(newModuleList, index);
            _AddModule(athenaTransportLinkAdapter, athenaTransportLinkModule);
        }
        parcArrayList_Destroy(&newModuleList);
    }
    return _LookupModule(athenaTransportLinkAdapter, moduleName);
}
static AthenaTransportLinkModule *
_LoadModule(AthenaTransportLinkAdapter *athenaTransportLinkAdapter, const char *moduleName)
{
    assertTrue(_LookupModule(athenaTransportLinkAdapter, moduleName) == NULL,
               "attempt to load an already loaded module");

    // Derive the entry initialization name from the provided module name
    const char *moduleEntry;
    moduleEntry = _moduleNameToInitMethod(moduleName);

    // Check to see if the module was statically linked in.
    void *linkModule = RTLD_DEFAULT;
    ModuleInit _init = dlsym(linkModule, moduleEntry);

    // If not statically linked in, look for a shared library and load it from there
    if (_init == NULL) {
        // Derive the library name from the provided module name
        const char *moduleLibrary;
        moduleLibrary = _moduleNameToLibrary(moduleName);

        void *linkModule = dlopen(moduleLibrary, RTLD_NOW | RTLD_GLOBAL);
        parcMemory_Deallocate(&moduleLibrary);

        // If the shared library wasn't found, look for the symbol in our existing image.  This
        // allows a link module to be linked directly into Athena without modifying the forwarder.
        if (linkModule == NULL) {
            parcLog_Error(athenaTransportLinkAdapter_GetLogger(athenaTransportLinkAdapter),
                          "Unable to dlopen %s: %s", moduleName, dlerror());
            parcMemory_Deallocate(&moduleEntry);
            errno = ENOENT;
            return NULL;
        }

        _init = dlsym(linkModule, moduleEntry);
        if (_init == NULL) {
            parcLog_Error(athenaTransportLinkAdapter_GetLogger(athenaTransportLinkAdapter),
                          "Unable to find %s module _init method: %s", moduleName, dlerror());
            parcMemory_Deallocate(&moduleEntry);
            dlclose(linkModule);
            errno = ENOENT;
            return NULL;
        }
    }
    parcMemory_Deallocate(&moduleEntry);

    // Call the initialization method.
    PARCArrayList *moduleList = _init();
    if (moduleList == NULL) { // if the init method fails, unload the module if it was loaded
        parcLog_Error(athenaTransportLinkAdapter_GetLogger(athenaTransportLinkAdapter),
                      "Empty module list returned from %s module", moduleName);
        if (linkModule != RTLD_DEFAULT) {
            dlclose(linkModule);
        }
        errno = ENOENT;
        return NULL;
    }

    // Process each link module instance (typically only one)
    for (int index = 0; index < parcArrayList_Size(moduleList); index++) {
        AthenaTransportLinkModule *athenaTransportLinkModule = parcArrayList_Get(moduleList, index);
        _AddModule(athenaTransportLinkAdapter, athenaTransportLinkModule);
    }
    parcArrayList_Destroy(&moduleList);

    return _LookupModule(athenaTransportLinkAdapter, moduleName);
}