GEODE-2484: Removes ACE_DLL (#591)

Replaces with boost::dll.
diff --git a/clicache/src/Utils.cpp b/clicache/src/Utils.cpp
index 8b54cce..4480b73 100644
--- a/clicache/src/Utils.cpp
+++ b/clicache/src/Utils.cpp
@@ -67,11 +67,6 @@
       return nullptr;
     }
 
-    System::Int32 Utils::LastError::get( )
-    {
-       return apache::geode::client::Utils::getLastError( );
-    }
-
     }  // namespace Client
   }  // namespace Geode
 }  // namespace Apache
diff --git a/clicache/src/Utils.hpp b/clicache/src/Utils.hpp
index bec8a6e..60b120b 100644
--- a/clicache/src/Utils.hpp
+++ b/clicache/src/Utils.hpp
@@ -37,50 +37,43 @@
     /// <summary>
     /// Some static utility methods.
     /// </summary>
-				public ref class Utils STATICCLASS
-				{
-				public:
+    public ref class Utils STATICCLASS
+    {
+    public:
 
-					/// <summary>
-					/// Load a method from the given assembly path using the default
-					/// constructor (if not a static method) of the given type.
-					/// </summary>
-					/// <param name="assemblyPath">The path of the assembly.</param>
-					/// <param name="typeName">
-					/// The name of the class containing the method.
-					/// </param>
-					/// <param name="methodName">The name of the method.</param>
-					/// <returns>
-					/// The <c>System.Reflection.MethodInfo</c> for the given method,
-					/// or null if the method is not found.
-					/// </returns>
-					static MethodInfo^ LoadMethod( String^ assemblyPath,
-						String^ typeName, String^ methodName);
+      /// <summary>
+      /// Load a method from the given assembly path using the default
+      /// constructor (if not a static method) of the given type.
+      /// </summary>
+      /// <param name="assemblyPath">The path of the assembly.</param>
+      /// <param name="typeName">
+      /// The name of the class containing the method.
+      /// </param>
+      /// <param name="methodName">The name of the method.</param>
+      /// <returns>
+      /// The <c>System.Reflection.MethodInfo</c> for the given method,
+      /// or null if the method is not found.
+      /// </returns>
+      static MethodInfo^ LoadMethod( String^ assemblyPath,
+	      String^ typeName, String^ methodName);
 
-					/// <summary>
-					/// Load a method from the given assembly name using the default
-					/// constructor (if not a static method) of the given type.
-					/// </summary>
-					/// <param name="assemblyName">The name of the assembly.</param>
-					/// <param name="typeName">
-					/// The name of the class containing the method.
-					/// </param>
-					/// <param name="methodName">The name of the method.</param>
-					/// <returns>
-					/// The <c>System.Reflection.MethodInfo</c> for the given method,
-					/// or null if the method is not found.
-					/// </returns>
-					static MethodInfo^ LoadMethodFrom( String^ assemblyName,
-						String^ typeName, String^ methodName);
+      /// <summary>
+      /// Load a method from the given assembly name using the default
+      /// constructor (if not a static method) of the given type.
+      /// </summary>
+      /// <param name="assemblyName">The name of the assembly.</param>
+      /// <param name="typeName">
+      /// The name of the class containing the method.
+      /// </param>
+      /// <param name="methodName">The name of the method.</param>
+      /// <returns>
+      /// The <c>System.Reflection.MethodInfo</c> for the given method,
+      /// or null if the method is not found.
+      /// </returns>
+      static MethodInfo^ LoadMethodFrom( String^ assemblyName,
+	      String^ typeName, String^ methodName);
 
-					/// <summary>
-					/// Utility method to get the calling thread's last system error code.
-					/// </summary>
-					static property System::Int32 LastError
-					{
-						System::Int32 get( );
-					}
-				};
+    };
     }  // namespace Client
   }  // namespace Geode
 }  // namespace Apache
diff --git a/cppcache/src/CacheXmlParser.hpp b/cppcache/src/CacheXmlParser.hpp
index 1353d33..439a00d 100644
--- a/cppcache/src/CacheXmlParser.hpp
+++ b/cppcache/src/CacheXmlParser.hpp
@@ -162,8 +162,8 @@
         // this is a managed library
         (loader)(libraryName.c_str(), functionName.c_str());
       } else {
-        apache::geode::client::Utils::getFactoryFunction(libraryName,
-                                                         functionName);
+        apache::geode::client::Utils::getFactoryFunction<void*()>(libraryName,
+                                                                  functionName);
       }
     } catch (IllegalArgumentException& ex) {
       throw CacheXmlException(ex.what());
diff --git a/cppcache/src/RegionAttributes.cpp b/cppcache/src/RegionAttributes.cpp
index 32843c6..4276d71 100644
--- a/cppcache/src/RegionAttributes.cpp
+++ b/cppcache/src/RegionAttributes.cpp
@@ -67,9 +67,8 @@
       m_cacheLoader.reset((CacheXmlParser::managedCacheLoaderFn_)(
           m_cacheLoaderLibrary.c_str(), m_cacheLoaderFactory.c_str()));
     } else {
-      CacheLoader* (*funcptr)();
-      funcptr = reinterpret_cast<CacheLoader* (*)()>(Utils::getFactoryFunction(
-          m_cacheLoaderLibrary, m_cacheLoaderFactory));
+      auto funcptr = Utils::getFactoryFunction<CacheLoader*()>(
+          m_cacheLoaderLibrary, m_cacheLoaderFactory);
       m_cacheLoader.reset(funcptr());
     }
   }
@@ -84,9 +83,8 @@
       m_cacheWriter.reset((CacheXmlParser::managedCacheWriterFn_)(
           m_cacheWriterLibrary.c_str(), m_cacheWriterFactory.c_str()));
     } else {
-      CacheWriter* (*funcptr)();
-      funcptr = reinterpret_cast<CacheWriter* (*)()>(Utils::getFactoryFunction(
-          m_cacheWriterLibrary, m_cacheWriterFactory));
+      auto funcptr = Utils::getFactoryFunction<CacheWriter*()>(
+          m_cacheWriterLibrary, m_cacheWriterFactory);
       m_cacheWriter.reset(funcptr());
     }
   }
@@ -101,10 +99,8 @@
       m_cacheListener.reset((CacheXmlParser::managedCacheListenerFn_)(
           m_cacheListenerLibrary.c_str(), m_cacheListenerFactory.c_str()));
     } else {
-      CacheListener* (*funcptr)();
-      funcptr =
-          reinterpret_cast<CacheListener* (*)()>(Utils::getFactoryFunction(
-              m_cacheListenerLibrary, m_cacheListenerFactory));
+      auto funcptr = Utils::getFactoryFunction<CacheListener*()>(
+          m_cacheListenerLibrary, m_cacheListenerFactory);
       m_cacheListener.reset(funcptr());
     }
   }
@@ -121,10 +117,8 @@
           m_partitionResolverLibrary.c_str(),
           m_partitionResolverFactory.c_str()));
     } else {
-      PartitionResolver* (*funcptr)();
-      funcptr =
-          reinterpret_cast<PartitionResolver* (*)()>(Utils::getFactoryFunction(
-              m_partitionResolverLibrary, m_partitionResolverFactory));
+      auto funcptr = Utils::getFactoryFunction<PartitionResolver*()>(
+          m_partitionResolverLibrary, m_partitionResolverFactory);
       m_partitionResolver.reset(funcptr());
     }
   }
@@ -140,10 +134,8 @@
       m_persistenceManager.reset((CacheXmlParser::managedPersistenceManagerFn_)(
           m_persistenceLibrary.c_str(), m_persistenceFactory.c_str()));
     } else {
-      PersistenceManager* (*funcptr)();
-      funcptr =
-          reinterpret_cast<PersistenceManager* (*)()>(Utils::getFactoryFunction(
-              m_persistenceLibrary, m_persistenceFactory));
+      auto funcptr = Utils::getFactoryFunction<PersistenceManager*()>(
+          m_persistenceLibrary, m_persistenceFactory);
       m_persistenceManager.reset(funcptr());
     }
   }
diff --git a/cppcache/src/Utils.cpp b/cppcache/src/Utils.cpp
index b7b2c32..17227c5 100644
--- a/cppcache/src/Utils.cpp
+++ b/cppcache/src/Utils.cpp
@@ -21,18 +21,16 @@
 #include <cstdio>
 #include <cstdlib>
 #include <iomanip>
-#include <sstream>
 
-#include <ace/DLL.h>
 #include <ace/INET_Addr.h>
 #include <ace/OS.h>
+#include <boost/asio.hpp>
+#include <boost/dll/import.hpp>
 
 namespace apache {
 namespace geode {
 namespace client {
 
-int32_t Utils::getLastError() { return ACE_OS::last_error(); }
-
 std::string Utils::getEnv(const char* varName) {
   std::string env;
   if (const auto varValue = std::getenv(varName)) {
@@ -151,18 +149,59 @@
   return resStr;
 }
 
-void* Utils::getFactoryFunction(const std::string& lib,
-                                const std::string& funcName) {
-  ACE_DLL dll;
-  if (dll.open(lib.c_str(), ACE_DEFAULT_SHLIB_MODE, 0) == -1) {
-    throw IllegalArgumentException("cannot open library: " + lib);
+/**
+ * Finds, loads and keeps a copy of requested shared library. Future
+ * improvements should use the boost::dll::import to maintain references to
+ * shared libraries rather than a synchronized global structure.
+ *
+ * Uses similar options ans search patterns to the original ACE_DLL
+ * implementation.
+ *
+ * @param libraryName to find or load
+ * @return found or loaded shared library
+ * @throws IllegalArgumentException if library is not found or otherwise
+ * unloadable.
+ */
+const boost::dll::shared_library& getSharedLibrary(
+    const std::string& libraryName) {
+  static std::mutex sharedLibrariesMutex;
+  static std::unordered_map<std::string,
+                            std::shared_ptr<boost::dll::shared_library>>
+      sharedLibraries;
+
+  std::lock_guard<decltype(sharedLibrariesMutex)> lock(sharedLibrariesMutex);
+
+  const auto& find = sharedLibraries.find(libraryName);
+  if (find == sharedLibraries.end()) {
+    try {
+      return *sharedLibraries
+                  .emplace(
+                      libraryName,
+                      std::make_shared<boost::dll::shared_library>(
+                          libraryName,
+                          boost::dll::load_mode::rtld_global |
+                              boost::dll::load_mode::rtld_lazy |
+                              boost::dll::load_mode::append_decorations |
+                              boost::dll::load_mode::search_system_folders))
+                  .first->second;
+    } catch (const boost::dll::fs::system_error& e) {
+      throw IllegalArgumentException("cannot open library: " + libraryName +
+                                     ": reason: " + e.what());
+    }
   }
-  void* func = dll.symbol(funcName.c_str());
-  if (func == nullptr) {
+
+  return *find->second;
+}
+
+void* Utils::getFactoryFunctionVoid(const std::string& lib,
+                                    const std::string& funcName) {
+  try {
+    const auto& sharedLibrary = getSharedLibrary(lib);
+    return reinterpret_cast<void*>(sharedLibrary.get<void*()>(funcName));
+  } catch (const boost::dll::fs::system_error&) {
     throw IllegalArgumentException("cannot find factory function " + funcName +
                                    " in library " + lib);
   }
-  return func;
 }
 
 std::string Utils::convertBytesToString(const uint8_t* bytes, size_t length,
diff --git a/cppcache/src/Utils.hpp b/cppcache/src/Utils.hpp
index ba9c80d..52a6041 100644
--- a/cppcache/src/Utils.hpp
+++ b/cppcache/src/Utils.hpp
@@ -58,7 +58,6 @@
    * On windows the maximum length of value supported is 8191.
    */
   static std::string getEnv(const char* varName);
-  static int32_t getLastError();
 
 #ifdef __GNUC__
   inline static char* _gnuDemangledName(const char* typeIdName, size_t& len) {
@@ -167,14 +166,16 @@
                                           size_t maxLength = _GF_MSG_LIMIT);
 
   /**
-   * lib should be in the form required by ACE_DLL, typically just like
-   * specifying
-   * a
-   * lib in java System.loadLibrary( "x" ); Where x is a component of the name
-   * lib<x>.so on unix, or <x>.dll on windows.
+   * lib should be in the form originally required by ACE_DLL, typically just
+   * like specifying a lib in java System.loadLibrary( "x" ); Where x is a
+   * component of the name lib<x>.so on unix, or <x>.dll on windows.
    */
-  static void* getFactoryFunction(const std::string& lib,
-                                  const std::string& funcName);
+  template <typename T>
+  static T* getFactoryFunction(const std::string& libraryName,
+                               const std::string& functionName) {
+    return reinterpret_cast<T*>(
+        getFactoryFunctionVoid(libraryName, functionName));
+  }
 
   /**
    * Convert the byte array to a string as "%d %d ...".
@@ -192,6 +193,10 @@
     return convertBytesToString(reinterpret_cast<const uint8_t*>(bytes), length,
                                 maxLength);
   }
+
+ private:
+  static void* getFactoryFunctionVoid(const std::string& lib,
+                                      const std::string& funcName);
 };
 
 // Generate random numbers 0 to max-1