Request for Changes-15: Improve ApplicationRegistry for application loading

From OTBWiki
Jump to: navigation, search

[Request for Changes - 15] Improve ApplicationRegistry for application loading

Status

Summary

This RFC fixes the issue Mantis-1082 and offers a bit more in order to enable a good integration of OTBApplications in Monteverdi 3.0

Rationale

Initially the problem was the use of the function ReHash() after that custom factories in OTB (such as IOFactories) are registered. Then it also appeared that the manual loading of Applications from shared libs (with a dlopen() ) was not doing the consequent dlclose() after the application is deleted.

Implementation details

Classes and files

M       Modules/Wrappers/ApplicationEngine/include/otbWrapperApplicationRegistry.h
M       Modules/Wrappers/ApplicationEngine/src/otbWrapperApplicationRegistry.cxx

The core of this RFC is the fix and improvement of the class otb::Wrapper::ApplicationRegistry. This class is used to instanciate Applications from their name. In the past, it used the ITK factory mechanism to load them : all shared library seen by the environment path ITK_AUTOLOAD_PATH are loaded and registered in ITK factories. After a performance improvement, an application can be loaded simply by loading the right shared lib (using the OTB_APPLICATION_PATH variable), and instanciating the application inside (see ApplicationRegistry::CreateApplicationFaster).

The main modifications for this class are :

  • method CreateApplication(const std::string& name, bool useFactory=true) has an optional boolean argument 'useFactory' that enables application loading from ITK factories if CreateApplicationFaster() doesn't find anything
  • method GetAvailableApplication(bool useFactory=true) has an optional boolean argument that enables the search in ITK factories to list available applications. In all cases, the search is first done in shared libraries from OTB_APPLICATION_PATH, and it doesn't call's anymore the ReHash() of ITK factories.
  • remove private method RefreshApplicationFactories() : not needed anymore with the new mechanism.
  • new private method LoadApplicationFromPath() : tries to load an application with a given name using a shared lib path. On success, returns the application pointer and register the pair (Application*, LibHandle*) in a static list. In addition, a delete callback is added to the application so that it will unregister itself from static list on delete. On failure, the library is closed, and an empty pointer is returned.
  • method CreateApplicationFaster() : now calls LoadApplicationFromPath().
  • new class ApplicationPrivateRegistry defined only in cxx, to store and manage the library handles corresponding to shared libs opended during application creation. There is a static instance of this class. It allows to add a new pair, unregister a deleted application, clean the static list by releasing unused handles, and clear everything in destructor.
  • new method GetApplicationPath() : returns the search path OTB_APPLICATION_PATH
M       Modules/Wrappers/CommandLine/src/otbWrapperCommandLineLauncher.cxx
M       Modules/Wrappers/QtWidget/src/otbApplicationLauncherQt.cxx

These two launchers only check OTB_APPLICATION_PATH on failure.

Applications

Tests

M       Modules/Applications/AppTest/test/otbWrapperApplicationDocTests.cxx
M       Modules/Wrappers/QtWidget/test/otbWrapperQtWidgetShowWidget.cxx
M       Modules/Wrappers/SWIG/test/java/CMakeLists.txt
M       Modules/Wrappers/SWIG/test/python/CMakeLists.txt

Clean these tests and make sure they use the new OTB_APPLICATION_PATH.

Dashboard results here

Documentation

TODO : Update CookBook, SoftwareGuide to explain the use of OTB_APPLICATION_PATH and old ITK_AUTOLOAD_PATH.

Additional notes

Full patch

diff --git a/Modules/Applications/AppTest/test/otbWrapperApplicationDocTests.cxx b/Modules/Applications/AppTest/test/otbWrapperApplicationDocTests.cxx
index 01dc19c..1fbaf04 100644
--- a/Modules/Applications/AppTest/test/otbWrapperApplicationDocTests.cxx
+++ b/Modules/Applications/AppTest/test/otbWrapperApplicationDocTests.cxx
@@ -39,7 +39,6 @@ int otbWrapperApplicationDocTest(int argc, char* argv[])
     std::copy(argv + 1, argv + argc, std::back_inserter(modulePathList));
 
     // Load the path in the environment
-    std::string specificEnv("ITK_AUTOLOAD_PATH=");
     std::list<std::string>::const_iterator it = modulePathList.begin();
     while( it != modulePathList.end() )
       {
diff --git a/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplicationRegistry.h b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplicationRegistry.h
index 4eeb7d7..ba6a467 100644
--- a/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplicationRegistry.h
+++ b/Modules/Wrappers/ApplicationEngine/include/otbWrapperApplicationRegistry.h
@@ -58,16 +58,21 @@ public:
   /** Add the specified path to the list of application search path */
   static void AddApplicationPath(std::string path);
 
+  /** Return the application search path */
+  static std::string GetApplicationPath();
+
   /** Return the list of available applications */
-  static std::vector<std::string> GetAvailableApplications();
+  static std::vector<std::string> GetAvailableApplications(bool useFactory=true);
 
   /** Create the specified Application */
-  static Application::Pointer CreateApplication(const std::string& applicationName);
+  static Application::Pointer CreateApplication(const std::string& applicationName, bool useFactory=true);
 
   /** Create the specified Application (faster)
    *  method using dynamic library name to load the right module */
   static Application::Pointer CreateApplicationFaster(const std::string& applicationName);
 
+  /** Clean registry by releasing unused modules */
+  static void CleanRegistry();
 
 protected:
   ApplicationRegistry();
@@ -76,8 +81,9 @@ protected:
 private:
   ApplicationRegistry(const Self&); //purposely not implemented
   void operator=(const Self&); //purposely not implemented
-  
-  static void RefreshApplicationFactories();
+
+  /** Load an application from a shared library */
+  static Application::Pointer LoadApplicationFromPath(std::string path,std::string name);
 
 };
 
diff --git a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplicationRegistry.cxx b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplicationRegistry.cxx
index 4987535..52c050e 100644
--- a/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplicationRegistry.cxx
+++ b/Modules/Wrappers/ApplicationEngine/src/otbWrapperApplicationRegistry.cxx
@@ -20,6 +20,10 @@
 #include "otbMacro.h"
 #include "itksys/SystemTools.hxx"
 #include "itkDynamicLoader.h"
+#include "itkDirectory.h"
+#include "itkMutexLock.h"
+#include "itkMutexLockHolder.h"
+
 #include <iterator>
 
 namespace otb
@@ -27,6 +31,97 @@ namespace otb
 namespace Wrapper
 {
 
+// Constant : environment variable for application path
+static const char OTB_APPLICATION_VAR[] = "OTB_APPLICATION_PATH";
+
+class ApplicationPrivateRegistry
+{
+public:
+  typedef std::pair<Application*, void* > AppHandlePairType;
+  typedef std::list<AppHandlePairType>    AppHandleContainerType;
+
+  /** Add a pair (application, library handle) in the private registry */
+  bool AddPair(Application *app, void *handle)
+    {
+    AppHandlePairType pair;
+    if (app && handle)
+      {
+      // mutex lock to ensure thread safety
+      itk::MutexLockHolder<itk::SimpleMutexLock> mutexHolder(m_Mutex);
+      pair.first = app;
+      pair.second = handle;
+      m_Container.push_back(pair);
+      return true;
+      }
+    return false;
+    }
+
+  /** When an application is deleted, unregister its pointer from private registry */
+  void UnregisterApp(const Application *app)
+    {
+    if (app)
+      {
+      // mutex lock to ensure thread safety
+      itk::MutexLockHolder<itk::SimpleMutexLock> mutexHolder(m_Mutex);
+      AppHandleContainerType::iterator it = m_Container.begin();
+      while (it != m_Container.end())
+        {
+        if ((*it).first == app)
+          {
+          (*it).first = NULL;
+          }
+        ++it;
+        }
+      }
+    }
+
+  /** Release the library handles from applications already deleted */
+  void ReleaseUnusedHandle()
+    {
+    itk::MutexLockHolder<itk::SimpleMutexLock> mutexHolder(m_Mutex);
+    AppHandleContainerType::iterator it;
+    for (it = m_Container.begin() ; it != m_Container.end() ; ++it)
+      {
+      if ((*it).first == NULL)
+        {
+        itk::DynamicLoader::CloseLibrary( (*it).second);
+        (*it).second = NULL;
+        }
+      }
+    m_Container.remove(AppHandlePairType(NULL,NULL));
+    }
+
+  /** close all handles at program exit */
+  ~ApplicationPrivateRegistry()
+  {
+  AppHandleContainerType::iterator it;
+  for (it = m_Container.begin() ; it != m_Container.end() ; ++it)
+    {
+    itk::DynamicLoader::CloseLibrary( (*it).second);
+    }
+  m_Container.clear();
+  }
+
+private:
+  AppHandleContainerType m_Container;
+
+  itk::SimpleMutexLock m_Mutex;
+};
+// static finalizer to close opened libraries
+static ApplicationPrivateRegistry m_ApplicationPrivateRegistryGlobal;
+
+// Define callbacks to unregister applications in ApplicationPrivateRegistry
+void DeleteAppCallback(itk::Object *obj,const itk::EventObject &, void *)
+  {
+  Application *appPtr = dynamic_cast<Application*>(obj);
+  m_ApplicationPrivateRegistryGlobal.UnregisterApp(appPtr);
+  }
+void DeleteAppConstCallback(const itk::Object *obj,const itk::EventObject &, void *)
+  {
+  const Application *appPtr = dynamic_cast<const Application*>(obj);
+  m_ApplicationPrivateRegistryGlobal.UnregisterApp(appPtr);
+  }
+
 ApplicationRegistry::ApplicationRegistry()
 {
 }
@@ -39,7 +134,7 @@ void
 ApplicationRegistry::SetApplicationPath(std::string newpath)
 {
   std::ostringstream putEnvPath;
-  putEnvPath << "OTB_APPLICATION_PATH=" << newpath;
+  putEnvPath << OTB_APPLICATION_VAR << "=" << newpath;
 
   // do NOT use putenv() directly, since the string memory must be managed carefully
   itksys::SystemTools::PutEnv(putEnvPath.str().c_str());
@@ -49,10 +144,10 @@ void
 ApplicationRegistry::AddApplicationPath(std::string newpath)
 {
   std::ostringstream putEnvPath;
-  putEnvPath << "OTB_APPLICATION_PATH=";
+  putEnvPath << OTB_APPLICATION_VAR <<"=";
 
   // Can be NULL if the env var is not set
-  const char* currentEnv = itksys::SystemTools::GetEnv("OTB_APPLICATION_PATH");
+  const char* currentEnv = itksys::SystemTools::GetEnv(OTB_APPLICATION_VAR);
 
 #if defined(WIN32)
   const char pathSeparator = ';';
@@ -71,35 +166,48 @@ ApplicationRegistry::AddApplicationPath(std::string newpath)
   itksys::SystemTools::PutEnv(putEnvPath.str().c_str());
 }
 
+std::string
+ApplicationRegistry::GetApplicationPath()
+{
+  std::string ret;
+  // Can be NULL if the env var is not set
+  const char* currentEnv = itksys::SystemTools::GetEnv(OTB_APPLICATION_VAR);
+  if (currentEnv)
+    {
+    ret = std::string(currentEnv);
+    }
+  return ret;
+}
+
 Application::Pointer
-ApplicationRegistry::CreateApplication(const std::string& name)
+ApplicationRegistry::CreateApplication(const std::string& name, bool useFactory)
 {
   ApplicationPointer appli;
 
-  // Fast search
+  // Fast search : uses OTB_APPLICATION_PATH
   appli = ApplicationRegistry::CreateApplicationFaster(name);
   if (appli.IsNotNull())
     {
     return appli;
     }
 
-  // Classic search
-  ApplicationRegistry::RefreshApplicationFactories();
-
-  LightObject::Pointer possibleApp = itk::ObjectFactoryBase::CreateInstance(name.c_str());
-  
-  if (possibleApp.IsNotNull())
+  // Classic search : uses factories registered by ITK ( see ITK_AUTOLOAD_PATH )
+  if (useFactory)
     {
-    // Downcast
-    Application* app = dynamic_cast<Application*> (possibleApp.GetPointer());
-    if (app)
+    LightObject::Pointer possibleApp = itk::ObjectFactoryBase::CreateInstance(name.c_str());
+    if (possibleApp.IsNotNull())
       {
-        appli = app;
-        appli->Init();
-      }
-    else
-      {
-      otbMsgDevMacro( << "Error ApplicationRegistry factory did not return an Application: " << possibleApp->GetNameOfClass() << std::endl );
+      // Downcast
+      Application* app = dynamic_cast<Application*> (possibleApp.GetPointer());
+      if (app)
+        {
+          appli = app;
+          appli->Init();
+        }
+      else
+        {
+        otbMsgDevMacro( << "Error ApplicationRegistry factory did not return an Application: " << possibleApp->GetNameOfClass() << std::endl );
+        }
       }
     }
 
@@ -132,20 +240,12 @@ ApplicationRegistry::CreateApplicationFaster(const std::string& name)
   const char sep = '/';
 #endif
 
-  const char* otbAppPath = itksys::SystemTools::GetEnv("OTB_APPLICATION_PATH");
-  const char* itkLoadPath = itksys::SystemTools::GetEnv("ITK_AUTOLOAD_PATH");
-
-  std::ostringstream currentPath;
-  if (otbAppPath)
+  std::string otbAppPath = GetApplicationPath();
+  std::vector<itksys::String> pathList;
+  if (!otbAppPath.empty())
     {
-    currentPath << otbAppPath << pathSeparator;
+    pathList = itksys::SystemTools::SplitString(otbAppPath.c_str(),pathSeparator,false);
     }
-  if (itkLoadPath)
-    {
-    currentPath << itkLoadPath;
-    }
-
-  std::vector<itksys::String> pathList = itksys::SystemTools::SplitString(currentPath.str().c_str(),pathSeparator,false);
   for (unsigned int i=0 ; i<pathList.size() ; ++i)
     {
     std::string possiblePath = pathList[i];
@@ -155,41 +255,10 @@ ApplicationRegistry::CreateApplicationFaster(const std::string& name)
       }
     possiblePath += appLibName.str();
 
-    if (itksys::SystemTools::FileExists(possiblePath.c_str(),true))
+    appli = LoadApplicationFromPath(possiblePath,name);
+    if (appli.IsNotNull())
       {
-      itk::LibHandle   lib = itk::DynamicLoader::OpenLibrary( possiblePath.c_str() );
-      if ( lib )
-        {
-        /**
-         * Look for the symbol itkLoad in the library
-         */
-        ITK_LOAD_FUNCTION loadfunction =
-          ( ITK_LOAD_FUNCTION ) itk::DynamicLoader::GetSymbolAddress(lib, "itkLoad");
-        /**
-         * if the symbol is found call it to create the factory
-         * from the library
-         */
-        if ( loadfunction )
-          {
-          itk::ObjectFactoryBase *newfactory = ( *loadfunction )( );
-          // Downcast
-          ApplicationFactoryBase* appFactory = dynamic_cast<ApplicationFactoryBase*>(newfactory);
-
-          if (appFactory)
-            {
-            appli = appFactory->CreateApplication(name.c_str());
-            appli->Init();
-            break;
-            }
-          }
-        else
-          {
-          // In the past, some platforms crashed on the call
-          // DynamicLoader::CloseLibrary(lib) if the lib has symbols
-          // that the current executable is using.
-          itk::DynamicLoader::CloseLibrary(lib);
-          }
-        }
+      break;
       }
     }
 
@@ -197,38 +266,88 @@ ApplicationRegistry::CreateApplicationFaster(const std::string& name)
 }
 
 std::vector<std::string>
-ApplicationRegistry::GetAvailableApplications()
+ApplicationRegistry::GetAvailableApplications(bool useFactory)
 {
   ApplicationPointer appli;
+  std::set<std::string> appSet;
+
+  std::string appPrefix("otbapp_");
+  std::string appExtension = itksys::DynamicLoader::LibExtension();
+#ifdef __APPLE__
+  appExtension = ".dylib";
+#endif
 
-  ApplicationRegistry::RefreshApplicationFactories();
+#if defined(WIN32)
+  const char pathSeparator = ';';
+#else
+  const char pathSeparator = ':';
+#endif
 
-  std::list<ApplicationPointer> possibleApp;
-  std::list<LightObject::Pointer> allobjects = itk::ObjectFactoryBase::CreateAllInstance("otbWrapperApplication");
+#ifdef _WIN32
+  const char sep = '\\';
+#else
+  const char sep = '/';
+#endif
 
-  // Downcast and Sanity check
-  for (std::list<LightObject::Pointer>::iterator i = allobjects.begin(); i != allobjects.end(); ++i)
+  std::string otbAppPath = GetApplicationPath();
+  std::vector<itksys::String> pathList;
+  if (!otbAppPath.empty())
+    {
+    pathList = itksys::SystemTools::SplitString(otbAppPath.c_str(),pathSeparator,false);
+    }
+  for (unsigned int k=0 ; k<pathList.size() ; ++k)
     {
-    Application* io = dynamic_cast<Application*> (i->GetPointer());
-    if (io)
+    itk::Directory::Pointer dir = itk::Directory::New();
+    if (!dir->Load(pathList[k].c_str()))
       {
-      possibleApp.push_back(io);
+      continue;
       }
-    else
+    for (unsigned int i = 0; i < dir->GetNumberOfFiles(); i++)
       {
-      otbMsgDevMacro( "Error ApplicationRegistry factory did not return an Application: " << (*i)->GetNameOfClass() << std::endl );
+      const char *filename = dir->GetFile(i);
+      std::string sfilename(filename);
+      std::string::size_type extPos = sfilename.rfind(appExtension);
+      std::string::size_type prefixPos = sfilename.find(appPrefix);
+
+      // Check if current file is a shared lib with the right pattern
+      if (extPos + appExtension.size() == sfilename.size() &&
+          prefixPos == 0)
+        {
+        std::string name = sfilename.substr(appPrefix.size(),extPos-appPrefix.size());
+        std::string fullpath = pathList[k];
+        if (!fullpath.empty() && fullpath[fullpath.size() - 1] != sep)
+          {
+          fullpath.push_back(sep);
+          }
+        fullpath.append(sfilename);
+        appli = LoadApplicationFromPath(fullpath,name);
+        if (appli.IsNotNull())
+          {
+          appSet.insert(name);
+          }
+        appli = NULL;
+        }
       }
     }
 
-  // Get all the app names
-  // If ITK_AUTOLOAD_PATH contains several times the same path, then the same app appear several times
-  // Use a temporary std::set to fix this
-  std::set<std::string> appSet;
-  for(std::list<ApplicationPointer>::iterator k = possibleApp.begin();
-      k != possibleApp.end(); ++k)
+  if (useFactory)
     {
-    (*k)->Init();
-    appSet.insert((*k)->GetName());
+    std::list<LightObject::Pointer> allobjects = itk::ObjectFactoryBase::CreateAllInstance("otbWrapperApplication");
+    // Downcast and Sanity check
+    for (std::list<LightObject::Pointer>::iterator i = allobjects.begin(); i != allobjects.end(); ++i)
+      {
+      Application* app = dynamic_cast<Application*> (i->GetPointer());
+      if (app)
+        {
+        app->Init();
+        std::string curName(app->GetName());
+        appSet.insert(curName);
+        }
+      else
+        {
+        otbMsgDevMacro( << "Error ApplicationRegistry factory did not return an Application: " << (*i)->GetNameOfClass() << std::endl );
+        }
+      }
     }
 
   std::vector<std::string> appVec;
@@ -237,46 +356,57 @@ ApplicationRegistry::GetAvailableApplications()
 }
 
 void
-ApplicationRegistry::RefreshApplicationFactories()
+ApplicationRegistry::CleanRegistry()
 {
-  std::ostringstream putEnvPath;
-  putEnvPath << "ITK_AUTOLOAD_PATH=";
-
-  // Can be NULL if the env var is not set
-  const char* currentEnv = itksys::SystemTools::GetEnv("ITK_AUTOLOAD_PATH");
-
-  // OTB specific application path
-  const char* otbApplicationPath = itksys::SystemTools::GetEnv("OTB_APPLICATION_PATH");
-
-#if defined(WIN32)
-  const char pathSeparator = ';';
-#else
-  const char pathSeparator = ':';
-#endif
+  m_ApplicationPrivateRegistryGlobal.ReleaseUnusedHandle();
+}
 
-  if (otbApplicationPath)
-    {
-    putEnvPath << otbApplicationPath << pathSeparator;
-    }
+Application::Pointer
+ApplicationRegistry::LoadApplicationFromPath(std::string path,std::string name)
+{
+  Application::Pointer appli;
 
-  if (currentEnv)
+  if (itksys::SystemTools::FileExists(path.c_str(),true))
     {
-    putEnvPath << currentEnv;
-    }
-
-  // do NOT use putenv() directly, since the string memory must be managed carefully
-  itksys::SystemTools::PutEnv(putEnvPath.str().c_str());
-
-  // Reload factories to take into account new path
-  itk::ObjectFactoryBase::ReHash();
+    itk::LibHandle lib = itk::DynamicLoader::OpenLibrary(path.c_str());
+    if (lib)
+      {
+      /**
+       * Look for the symbol itkLoad in the library
+       */
+      ITK_LOAD_FUNCTION loadfunction =
+        ( ITK_LOAD_FUNCTION ) itk::DynamicLoader::GetSymbolAddress(lib, "itkLoad");
+      /**
+       * if the symbol is found call it to create the factory
+       * from the library
+       */
+      if ( loadfunction )
+        {
+        itk::ObjectFactoryBase *newfactory = ( *loadfunction )( );
+        // Downcast
+        ApplicationFactoryBase* appFactory = dynamic_cast<ApplicationFactoryBase*>(newfactory);
 
-  std::ostringstream resetEnvPath;
-  resetEnvPath << "ITK_AUTOLOAD_PATH=";
-  if (currentEnv)
-    {
-    resetEnvPath << currentEnv;
+        if (appFactory)
+          {
+          appli = appFactory->CreateApplication(name.c_str());
+          if (appli.IsNotNull())
+            {
+            appli->Init();
+            // register library handle
+            m_ApplicationPrivateRegistryGlobal.AddPair(appli.GetPointer(), (void*) lib);
+            // set a callback on DeleteEvent
+            itk::CStyleCommand::Pointer command = itk::CStyleCommand::New();
+            command->SetCallback(&DeleteAppCallback);
+            command->SetConstCallback(&DeleteAppConstCallback);
+            appli->AddObserver(itk::DeleteEvent(),command);
+            return appli;
+            }
+          }
+        }
+      itk::DynamicLoader::CloseLibrary(lib);
+      }
     }
-  itksys::SystemTools::PutEnv(resetEnvPath.str().c_str());
+  return appli;
 }
 
 
diff --git a/Modules/Wrappers/CommandLine/src/otbWrapperCommandLineLauncher.cxx b/Modules/Wrappers/CommandLine/src/otbWrapperCommandLineLauncher.cxx
index dcc59f9..c3cd479 100644
--- a/Modules/Wrappers/CommandLine/src/otbWrapperCommandLineLauncher.cxx
+++ b/Modules/Wrappers/CommandLine/src/otbWrapperCommandLineLauncher.cxx
@@ -321,9 +321,8 @@ void CommandLineLauncher::LoadApplication()
   if (m_Application.IsNull())
     {
     std::cerr << "ERROR: Could not find application \"" << moduleName << "\"" << std::endl;
-
-    const char * ITK_AUTOLOAD_PATH = itksys::SystemTools::GetEnv("ITK_AUTOLOAD_PATH");
-    std::cerr << "ERROR: Module search path: " << (ITK_AUTOLOAD_PATH ? ITK_AUTOLOAD_PATH : "none (check ITK_AUTOLOAD_PATH)") << std::endl;
+    std::string modulePath = ApplicationRegistry::GetApplicationPath();
+    std::cerr << "ERROR: Module search path: " << (modulePath.empty() ? "none (check OTB_APPLICATION_PATH)" : modulePath) << std::endl;
 
     std::vector<std::string> list = ApplicationRegistry::GetAvailableApplications();
     if (list.size() == 0)
diff --git a/Modules/Wrappers/QtWidget/src/otbApplicationLauncherQt.cxx b/Modules/Wrappers/QtWidget/src/otbApplicationLauncherQt.cxx
index 24036ac..99e0779 100644
--- a/Modules/Wrappers/QtWidget/src/otbApplicationLauncherQt.cxx
+++ b/Modules/Wrappers/QtWidget/src/otbApplicationLauncherQt.cxx
@@ -53,7 +53,6 @@ int main(int argc, char* argv[])
     std::copy(argv + 2, argv + argc, std::back_inserter(modulePathList));
 
     // Load the path in the environment
-    std::string specificEnv("ITK_AUTOLOAD_PATH=");
     std::list<std::string>::const_iterator it = modulePathList.begin();
     while( it != modulePathList.end() )
       {
@@ -68,9 +67,8 @@ int main(int argc, char* argv[])
 
     {
     std::cerr << "Could not find application " << moduleName << std::endl;
-
-    const char* modulePath = itksys::SystemTools::GetEnv("ITK_AUTOLOAD_PATH");
-    std::cout << "Module search path : " << (modulePath ? modulePath : "") << std::endl;
+    std::string modulePath = ApplicationRegistry::GetApplicationPath();
+    std::cout << "Module search path : " << modulePath << std::endl;
     std::vector<std::string> list = ApplicationRegistry::GetAvailableApplications();
 
     std::cout << "Available applications : " << (list.empty() ? "None" : "") << std::endl;
diff --git a/Modules/Wrappers/QtWidget/test/otbWrapperQtWidgetShowWidget.cxx b/Modules/Wrappers/QtWidget/test/otbWrapperQtWidgetShowWidget.cxx
index c3e3086..3dae376 100644
--- a/Modules/Wrappers/QtWidget/test/otbWrapperQtWidgetShowWidget.cxx
+++ b/Modules/Wrappers/QtWidget/test/otbWrapperQtWidgetShowWidget.cxx
@@ -41,7 +41,6 @@ int otbWrapperQtWidgetShowWidget(int argc, char* argv[])
     std::copy(argv + 1, argv + argc, std::back_inserter(modulePathList));
 
     // Load the path in the environment
-    std::string specificEnv("ITK_AUTOLOAD_PATH=");
     std::list<std::string>::const_iterator it = modulePathList.begin();
     while( it != modulePathList.end() )
       {
diff --git a/Modules/Wrappers/SWIG/test/java/CMakeLists.txt b/Modules/Wrappers/SWIG/test/java/CMakeLists.txt
index 993160e..3b0917f 100644
--- a/Modules/Wrappers/SWIG/test/java/CMakeLists.txt
+++ b/Modules/Wrappers/SWIG/test/java/CMakeLists.txt
@@ -1,7 +1,7 @@
 include( UseJava )
 
 set(TEST_DRIVER otbTestDriver
-    --add-before-env ITK_AUTOLOAD_PATH $<TARGET_FILE_DIR:otbapp_Smoothing>
+    --add-before-env OTB_APPLICATION_PATH $<TARGET_FILE_DIR:otbapp_Smoothing>
 )
 
 set( PATH_SEPARATOR ":")
diff --git a/Modules/Wrappers/SWIG/test/python/CMakeLists.txt b/Modules/Wrappers/SWIG/test/python/CMakeLists.txt
index e51c82f..1983b0e 100644
--- a/Modules/Wrappers/SWIG/test/python/CMakeLists.txt
+++ b/Modules/Wrappers/SWIG/test/python/CMakeLists.txt
@@ -1,7 +1,7 @@
 set(TEST_DRIVER otbTestDriver
     --add-before-env PYTHONPATH        "${OTBSWIGWrapper_BINARY_DIR}/src"
     --add-before-env PYTHONPATH        $<TARGET_FILE_DIR:_otbApplication>
-    --add-before-env ITK_AUTOLOAD_PATH $<TARGET_FILE_DIR:otbapp_Smoothing> )
+    --add-before-env OTB_APPLICATION_PATH $<TARGET_FILE_DIR:otbapp_Smoothing> )
 
 add_test( NAME pyTvSmoothing
           COMMAND ${TEST_DRIVER} Execute