Use dlsym to load all filters
[metaproxy-moved-to-github.git] / src / factory_filter.cpp
1 /* This file is part of Metaproxy.
2    Copyright (C) 2005-2013 Index Data
3
4 Metaproxy is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19 #include "config.hpp"
20
21 #include "factory_filter.hpp"
22
23 #if HAVE_DLFCN_H
24 #include <dlfcn.h>
25 #endif
26 #include <stdexcept>
27 #include <iostream>
28 #include <string>
29 #include <map>
30
31 namespace mp = metaproxy_1;
32
33 namespace metaproxy_1 {
34     class FactoryFilter::Rep {
35         typedef std::map<std::string, CreateFilterCallback> CallbackMap;
36         typedef std::map<std::string, CreateFilterCallback>::iterator
37             CallbackMapIt;
38     public:
39         friend class FactoryFilter;
40         CallbackMap m_fcm;
41         Rep();
42         ~Rep();
43     };
44 }
45
46 mp::FactoryFilter::NotFound::NotFound(const std::string message)
47     : std::runtime_error(message)
48 {
49 }
50
51 mp::FactoryFilter::Rep::Rep()
52 {
53 }
54
55 mp::FactoryFilter::Rep::~Rep()
56 {
57 }
58
59 mp::FactoryFilter::FactoryFilter() : m_p(new mp::FactoryFilter::Rep)
60 {
61
62 }
63
64 mp::FactoryFilter::~FactoryFilter()
65 {
66
67 }
68
69 bool mp::FactoryFilter::add_creator(const std::string &fi,
70                                     CreateFilterCallback cfc)
71 {
72     return m_p->m_fcm.insert(Rep::CallbackMap::value_type(fi, cfc)).second;
73 }
74
75
76 bool mp::FactoryFilter::drop_creator(std::string fi)
77 {
78     return m_p->m_fcm.erase(fi) == 1;
79 }
80
81 bool mp::FactoryFilter::exist(std::string fi)
82 {
83     Rep::CallbackMap::const_iterator it = m_p->m_fcm.find(fi);
84
85     if (it == m_p->m_fcm.end())
86     {
87         return false;
88     }
89     return true;
90 }
91
92 mp::filter::Base* mp::FactoryFilter::create(std::string fi)
93 {
94     Rep::CallbackMap::const_iterator it = m_p->m_fcm.find(fi);
95
96     if (it == m_p->m_fcm.end()){
97         std::string msg = "filter type '" + fi + "' not found";
98             throw NotFound(msg);
99     }
100     // call create function
101     return (it->second());
102 }
103
104 bool mp::FactoryFilter::have_dl_support()
105 {
106 #if HAVE_DLFCN_H
107     return true;
108 #else
109     return false;
110 #endif
111 }
112
113 bool mp::FactoryFilter::add_creator_dl(const std::string &fi,
114                                         const std::string &path)
115 {
116 #if HAVE_DLFCN_H
117     if (m_p->m_fcm.find(fi) != m_p->m_fcm.end())
118     {
119         return true;
120     }
121     std::string full_name = "metaproxy_1_filter_" + fi;
122
123     void *dl_handle = dlopen(0, RTLD_GLOBAL|RTLD_NOW);
124     void *dlsym_ptr = dlsym(dl_handle, full_name.c_str());
125
126     if (!dlsym_ptr)
127     {
128         std::string full_path = path + "/metaproxy_filter_" + fi + ".so";
129         dl_handle = dlopen(full_path.c_str(), RTLD_GLOBAL|RTLD_NOW);
130         if (!dl_handle)
131         {
132             const char *dl = dlerror();
133             std::cout << "dlopen " << full_path << " failed. dlerror=" << dl <<
134                 std::endl;
135             return false;
136         }
137         dlsym_ptr = dlsym(dl_handle, full_name.c_str());
138     }
139     if (!dlsym_ptr)
140     {
141         std::cout << "dlsym " << full_name << " failed\n";
142         return false;
143     }
144     struct metaproxy_1_filter_struct *s = (struct metaproxy_1_filter_struct *) dlsym_ptr;
145     return add_creator(fi, s->creator);
146 #else
147     return false;
148 #endif
149 }
150
151 /*
152  * Local variables:
153  * c-basic-offset: 4
154  * c-file-style: "Stroustrup"
155  * indent-tabs-mode: nil
156  * End:
157  * vim: shiftwidth=4 tabstop=8 expandtab
158  */
159