Skip to content

File NPPluginManager.cxx

File List > core > NPPluginManager.cxx

Go to the documentation of this file


#include "NPPluginManager.h"
#include "NPException.h"
#include "NPFunction.h"
#include <dlfcn.h>
#include <filesystem>
#include <fstream>
#include <iostream>
namespace fs = std::filesystem;
nptool::PluginManager::PluginManager() {}
nptool::PluginManager::~PluginManager() {
  // Stop services
}

void* nptool::PluginManager::LoadPlugin(std::string name, bool allow_absent_plugin) {
  // Is it already loaded?
  auto itH = m_handle.find(name);
  if (itH != m_handle.end())
    return m_handle[name];
  // Does it exist ?
  auto it = m_available.find(name);
  if (it != m_available.end()) {
    // find where is the project base directory
    bool found_project_base = false;
    fs::path root = ("/");
    fs::path project_base = fs::current_path();
    fs::path project_yaml("project.yaml");
    fs::path project_install("install");
    while (!(fs::exists(project_base / project_yaml) && fs::exists(project_base / project_yaml))) {
      project_base = project_base.parent_path();
      if (project_base == root) {
        break;
      }
    }
    if (project_base != root) {
      found_project_base = true;
    }

    nptool::message("green", "core", "PluginManager::LoadPlugin",
                    "Found project base directory: " + project_base.string());
    // try load a duplicate version of the library
    bool is_local = true;
    std::string local_path = it->second;
    auto pos = local_path.find_last_of("/");

    local_path = project_base.string() + "/install/lib/" + local_path.substr(pos + 1);
    void* handle = dlopen(local_path.c_str(), RTLD_LAZY | RTLD_GLOBAL);

    // get the error if any
    char* LibError = dlerror();
    std::string error;
    if (LibError) {
      error = LibError;
      if (error.find("usedToIdentifyRootClingByDlSym") == std::string::npos) {
        // fall back to
        handle = dlopen(it->second.c_str(), RTLD_LAZY | RTLD_GLOBAL);
        is_local = false;
        LibError = dlerror();
        if (LibError) {
          error = LibError;

          if (error.find("usedToIdentifyRootClingByDlSym") == std::string::npos) {
            std::string msg = "Fail to load plugin library with error: ";
            msg += LibError;
            throw nptool::Error("PluginManager", msg);
          }
        }
      }
    }
    if (is_local)
      nptool::message("green", "core", "PluginManager::LoadPlugin",
                      "Loaded duplicate plugin " + name + " at " + local_path);
    else
      nptool::message("green", "core", "PluginManager::LoadPlugin", "Loaded plugin " + name + " at " + it->second);

    m_handle[name] = handle;

    // Check for Data Input Constructor method
    std::shared_ptr<nptool::VDataInput> (*data_input_construct)();
    data_input_construct = (std::shared_ptr<nptool::VDataInput>(*)())dlsym(handle, "ConstructDataInput");
    if (data_input_construct) {
      m_DataInputConstruct[name] = data_input_construct;
    }

    // Check for Data Output Constructor method
    std::shared_ptr<nptool::VDataOutput> (*data_output_construct)();
    data_output_construct = (std::shared_ptr<nptool::VDataOutput>(*)())dlsym(handle, "ConstructDataOutput");
    if (data_output_construct) {
      m_DataOutputConstruct[name] = data_output_construct;
    }

    // Check for User Interface Constructor method
    std::shared_ptr<nptool::VUserInterface> (*user_interface_construct)();
    user_interface_construct = (std::shared_ptr<nptool::VUserInterface>(*)())dlsym(handle, "ConstructUserInterface");
    if (user_interface_construct) {
      m_UserInterfaceConstruct[name] = user_interface_construct;
    }

    // Check for User Analysis Constructor method
    std::shared_ptr<nptool::VUserAnalysis> (*user_analysis_construct)();
    user_analysis_construct = (std::shared_ptr<nptool::VUserAnalysis>(*)())dlsym(handle, "ConstructUserAnalysis");
    if (user_analysis_construct)
      m_UserAnalysisConstruct[name] = user_analysis_construct;

    // Check for Detector Constructor method
    std::shared_ptr<nptool::VDetector> (*detector_construct)();
    detector_construct = (std::shared_ptr<nptool::VDetector>(*)())dlsym(handle, "ConstructDetector");
    if (detector_construct)
      m_DetectorConstruct[name] = detector_construct;


    // Check for PrimaryGenerator Constructor method
    std::shared_ptr<nptool::VPrimaryGenerator> (*primary_construct)();
    primary_construct = (std::shared_ptr<nptool::VPrimaryGenerator>(*)())dlsym(handle, "ConstructPrimaryGenerator");
    if (primary_construct)
      m_PrimaryGeneratorConstruct[name] = primary_construct;

    // Check for ReactionGenerator Constructor method
    std::shared_ptr<nptool::VReactionGenerator> (*reaction_construct)();
    reaction_construct = (std::shared_ptr<nptool::VReactionGenerator>(*)())dlsym(handle, "ConstructReactionGenerator");
    if (reaction_construct)
      m_ReactionGeneratorConstruct[name] = reaction_construct;

    // Check for PhysicsProcess Constructor method
    std::shared_ptr<nptool::VPhysicsProcess> (*process_construct)();
    process_construct = (std::shared_ptr<nptool::VPhysicsProcess>(*)())dlsym(handle, "ConstructPhysicsProcess");
    if (process_construct)
      m_PhysicsProcessConstruct[name] = process_construct;
  }
  else if (!allow_absent_plugin) {
    std::string msg = "Requested plugin does not exist: ";
    msg += name;
    throw nptool::Warning("PluginManager", msg);
  }
  return m_handle[name];
}

void nptool::PluginManager::LoadPluginList(std::string file, bool allow_fail) {
  std::ifstream f(file);
  if (!f.is_open()) {
    if (!allow_fail) {
      std::string msg = "Fail to open plugin-token file " + file;
      throw nptool::Error("PluginManager", msg);
    }
    else
      return;
  }

  std::string package, token, lib;
  std::string path = getenv("NPTOOL_HOME");
  if (path.back() != '/')
    path += "/";
  path += getenv("NPTOOL_ENV");
  path += "/lib";
  while (f >> package >> token >> lib) {
    std::string lib_path = path + "/" + lib;
    m_available[token] = lib_path;
  }
}
std::shared_ptr<nptool::VDataInput> nptool::PluginManager::ConstructDataInput(std::string name) {
  // if plugin does not exist, load it
  if (m_handle.find(name) == m_handle.end())
    LoadPlugin(name);
  // check that the construct exist
  if (m_DataInputConstruct.find(name) != m_DataInputConstruct.end()) {
    auto input = m_DataInputConstruct[name]();
    m_inputs.insert(std::make_pair(name, input));
    return input;
  }
  return nullptr;
}
std::shared_ptr<nptool::VDataOutput> nptool::PluginManager::ConstructDataOutput(std::string name) {
  // if plugin does not exist, load it
  if (m_handle.find(name) == m_handle.end())
    LoadPlugin(name);
  // check that the construct exist
  if (m_DataOutputConstruct.find(name) != m_DataOutputConstruct.end()) {
    auto output = m_DataOutputConstruct[name]();
    m_outputs.insert(std::make_pair(name, output));
    return output;
  }
  return nullptr;
}
std::shared_ptr<nptool::VUserInterface> nptool::PluginManager::ConstructUserInterface(std::string name) {
  // if plugin does not exist, load it
  if (m_handle.find(name) == m_handle.end()) {
    LoadPlugin(name);
  }

  // check that the construct exist
  if (m_UserInterfaceConstruct.find(name) != m_UserInterfaceConstruct.end()) {
    auto interface = m_UserInterfaceConstruct[name]();
    m_interfaces.insert(std::make_pair(name, interface));
    return interface;
  }
  return nullptr;
}
std::shared_ptr<nptool::VUserAnalysis> nptool::PluginManager::ConstructUserAnalysis(std::string name) {
  // if plugin does not exist, load it
  if (m_handle.find(name) == m_handle.end())
    LoadPlugin(name);
  // check that the construct exist
  if (m_UserAnalysisConstruct.find(name) != m_UserAnalysisConstruct.end())
    return m_UserAnalysisConstruct[name]();
  return nullptr;
}
std::shared_ptr<nptool::VPrimaryGenerator> nptool::PluginManager::ConstructPrimaryGenerator(std::string name) {
  // if plugin does not exist, load it
  if (m_handle.find(name) == m_handle.end())
    LoadPlugin(name);
  // check that the construct exist
  if (m_PrimaryGeneratorConstruct.find(name) != m_PrimaryGeneratorConstruct.end())
    return m_PrimaryGeneratorConstruct[name]();
  return nullptr;
}
std::shared_ptr<nptool::VReactionGenerator> nptool::PluginManager::ConstructReactionGenerator(std::string name) {
  // if plugin does not exist, load it
  if (m_handle.find(name) == m_handle.end())
    LoadPlugin(name);
  // check that the construct exist
  if (m_ReactionGeneratorConstruct.find(name) != m_ReactionGeneratorConstruct.end())
    return m_ReactionGeneratorConstruct[name]();
  return nullptr;
}
std::shared_ptr<nptool::VPhysicsProcess> nptool::PluginManager::ConstructPhysicsProcess(std::string name) {
  // if plugin does not exist, load it
  if (m_handle.find(name) == m_handle.end())
    LoadPlugin(name);
  // check that the construct exist
  if (m_PhysicsProcessConstruct.find(name) != m_PhysicsProcessConstruct.end())
    return m_PhysicsProcessConstruct[name]();
  return nullptr;
}
std::shared_ptr<nptool::VDetector> nptool::PluginManager::ConstructDetector(std::string name) {
  // if plugin does not exist, load it
  if (m_handle.find(name) == m_handle.end())
    LoadPlugin(name);

  // check that the construct exist
  if (m_DetectorConstruct.find(name) != m_DetectorConstruct.end())
    return m_DetectorConstruct[name]();
  return nullptr;
}