From 951448f6b2cd0effb4b45a02c02908b75daec3d7 Mon Sep 17 00:00:00 2001
From: Marko Budiselic <mbudiselicbuda@gmail.com>
Date: Thu, 22 Oct 2015 23:54:28 +0200
Subject: [PATCH] dynamic lib load work in progress :P

---
 dc/README.md              |  6 +++++
 dc/example/db.hpp         | 19 +++++++++++++++
 dc/example/memsql.cpp     | 28 ++++++++++++++++++++++
 dc/example/mysql.cpp      | 28 ++++++++++++++++++++++
 dc/example/neo4j.cpp      | 28 ++++++++++++++++++++++
 dc/example/postgresql.cpp | 28 ++++++++++++++++++++++
 dc/test.cpp               | 50 ++++++++++++++++++++++++++++++++++-----
 7 files changed, 181 insertions(+), 6 deletions(-)
 create mode 100644 dc/example/db.hpp
 create mode 100644 dc/example/memsql.cpp
 create mode 100644 dc/example/mysql.cpp
 create mode 100644 dc/example/neo4j.cpp
 create mode 100644 dc/example/postgresql.cpp

diff --git a/dc/README.md b/dc/README.md
index 2bf28fe09..116d58797 100644
--- a/dc/README.md
+++ b/dc/README.md
@@ -1 +1,7 @@
 ## Dynamic Code
+
+```
+cd example
+clang++ -std=c++1y mysql.cpp -o ../tmp/mysql.so -shared -fPIC
+clang++ -std=c++1y test.cpp -o test.out -ldl
+```
diff --git a/dc/example/db.hpp b/dc/example/db.hpp
new file mode 100644
index 000000000..a507968df
--- /dev/null
+++ b/dc/example/db.hpp
@@ -0,0 +1,19 @@
+#ifndef MEMGRAPH_DL_EXAMPLE_DB_HPP
+#define MEMGRAPH_DL_EXAMPLE_DB_HPP
+
+#include <iostream>
+
+using namespace std;
+
+class db
+{
+public:
+    virtual void name() const;
+    virtual void type() const;
+    virtual ~db() {}
+};
+
+typedef db* (*produce_t)();
+typedef void (*destruct_t)(db*);
+
+#endif
diff --git a/dc/example/memsql.cpp b/dc/example/memsql.cpp
new file mode 100644
index 000000000..b8fa37ef4
--- /dev/null
+++ b/dc/example/memsql.cpp
@@ -0,0 +1,28 @@
+#include "db.hpp"
+
+class memsql : public db 
+{
+public:
+
+    void name() const override
+    {
+        cout << "MemSQL" << endl;
+    }
+
+    void type() const override
+    {
+        cout << "InMemory" << endl;
+    }
+
+    ~memsql() {}
+};
+
+extern "C" db* produce() 
+{
+    return new memsql();
+}
+
+extern "C" void destruct(db* p) 
+{
+    delete p;
+}
diff --git a/dc/example/mysql.cpp b/dc/example/mysql.cpp
new file mode 100644
index 000000000..3b6c1bb2c
--- /dev/null
+++ b/dc/example/mysql.cpp
@@ -0,0 +1,28 @@
+#include "db.hpp"
+
+class mysql : public db
+{
+public:
+
+    virtual void name() const
+    {
+        cout << "MySQL" << endl;
+    }
+
+    virtual void type() const
+    {
+        cout << "Relational" << endl;
+    }
+
+    ~mysql() {}
+};
+
+extern "C" db* produce()
+{
+    return new mysql();
+}
+
+extern "C" void destruct(db* p)
+{
+    delete p;
+}
diff --git a/dc/example/neo4j.cpp b/dc/example/neo4j.cpp
new file mode 100644
index 000000000..0418bed74
--- /dev/null
+++ b/dc/example/neo4j.cpp
@@ -0,0 +1,28 @@
+#include "db.hpp"
+
+class neo4j : public db
+{
+public:
+
+    void name() const override
+    {
+        cout << "Neo4j" << endl;
+    }
+
+    void type() const override
+    {
+        cout << "Graph" << endl;
+    }
+
+    ~neo4j() {}
+};
+
+extern "C" db* produce() 
+{
+    return new neo4j();
+}
+
+extern "C" void destruct(db* p) 
+{
+    delete p;
+}
diff --git a/dc/example/postgresql.cpp b/dc/example/postgresql.cpp
new file mode 100644
index 000000000..34b5445fe
--- /dev/null
+++ b/dc/example/postgresql.cpp
@@ -0,0 +1,28 @@
+#include "db.hpp"
+
+class postgresql : public db 
+{
+public:
+
+    void name() const override
+    {
+        cout << "PostgreSQL" << endl;
+    }
+
+    void type() const override
+    {
+        cout << "Relational" << endl;
+    }
+
+    ~postgresql() {}
+};
+
+extern "C" db* produce() 
+{
+    return new postgresql();
+}
+
+extern "C" void destruct(db* p) 
+{
+    delete p;
+}
diff --git a/dc/test.cpp b/dc/test.cpp
index 685aa8cde..ba582ad92 100644
--- a/dc/test.cpp
+++ b/dc/test.cpp
@@ -4,6 +4,8 @@
 #include <vector>
 #include <iterator>
 #include <cstdlib>
+#include <dlfcn.h>
+#include "example/db.hpp"
 
 // TODO: clang++ file.cpp -o file.so -shared -fPIC
 
@@ -32,15 +34,51 @@ std::string prints(const Args&... args)
     return join(strings, " ");
 }
 
+db* database(const std::string& lib_path, const std::string& factory_method)
+{
+    // load lib
+    void* db_lib = dlopen(lib_path.c_str(), RTLD_LAZY);
+    if (!db_lib) {
+        cerr << "Cannot load library: " << dlerror() << '\n';
+        return nullptr;
+    }
+    dlerror();
+
+    // load produce method
+    produce_t produce_db = (produce_t) dlsym(db_lib, factory_method.c_str());
+    const char* dlsym_error = dlerror();
+    if (dlsym_error) {
+        cerr << "Cannot load symbol create: " << dlsym_error << '\n';
+        return nullptr;
+    }
+
+    // load destroy method
+    // destruct_t destruct_db = (destruct_t) dlsym(db_lib, "destruct");
+    // dlsym_error = dlerror();
+    // if (dlsym_error) {
+    //     cerr << "Cannot load symbol destroy: " << dlsym_error << '\n';
+    //     return nullptr;
+    // }
+
+    db *instance = produce_db();
+
+    return instance;
+}
+
 int main() 
 {
-    string tmp_file_path = "tmp/tmp.cpp";
-    string tmp_so_path = "tmp/tmp.so";
-    string for_compile = "#include <iostream>\nint main() { std::cout << \"test\" << std::endl; return 0; }";
+    // string tmp_file_path = "tmp/tmp.cpp";
+    // string tmp_so_path = "tmp/tmp.so";
+    // string for_compile = "#include <iostream>\nint main() { std::cout << \"test\" << std::endl; return 0; }";
 
-    write(tmp_file_path, for_compile);
-    string test_command = prints("clang++", tmp_file_path, "-o", "test.out");
-    system(test_command.c_str());
+    // write(tmp_file_path, for_compile);
+    // string test_command = prints("clang++", tmp_file_path, "-o", "test.out");
+    // system(test_command.c_str());
+
+    db *mysql = database("./tmp/mysql.so", "produce");
+    if (mysql) {
+        mysql->name();
+    }
 
     return 0;
 }