1 /******************************************************************************
2 * Copyright (c) 2015, Bradley J Chambers (brad.chambers@gmail.com)
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following
8 * conditions are met:
9 *
10 *     * Redistributions of source code must retain the above copyright
11 *       notice, this list of conditions and the following disclaimer.
12 *     * Redistributions in binary form must reproduce the above copyright
13 *       notice, this list of conditions and the following disclaimer in
14 *       the documentation and/or other materials provided
15 *       with the distribution.
16 *     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
17 *       names of its contributors may be used to endorse or promote
18 *       products derived from this software without specific prior
19 *       written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 * OF SUCH DAMAGE.
33 ****************************************************************************/
34 
35 // The PluginManager was modeled very closely after the work of Gigi Sayfan in
36 // the Dr. Dobbs article:
37 // http://www.drdobbs.com/cpp/building-your-own-plugin-framework-part/206503957
38 // The original work was released under the Apache License v2.
39 
40 #pragma once
41 
42 #include <pdal/Log.hpp>
43 #include <pdal/PluginInfo.hpp>
44 #include <pdal/StageExtensions.hpp>
45 
46 #include <map>
47 #include <memory>
48 #include <mutex>
49 #include <string>
50 #include <vector>
51 #include <functional>
52 
53 
54 namespace pdal
55 {
56 
57 class DynamicLibrary;
58 
59 /*
60  * I think PluginManager can eventually be a private header, only accessible
61  * through the factories, but we'll leave it as public for now.
62  */
63 
64 template <typename T>
65 class PDAL_DLL PluginManager
66 {
67     struct Info
68     {
69         std::string name;
70         std::string link;
71         std::string description;
72         std::function<T *()> create;
73     };
74     typedef std::shared_ptr<DynamicLibrary> DynLibPtr;
75     typedef std::map<std::string, DynLibPtr> DynamicLibraryMap;
76     typedef std::map<std::string, Info> RegistrationInfoMap;
77 
78 public:
79     PluginManager(const PluginManager&) = delete;
80     PluginManager& operator=(const PluginManager&) = delete;
81     ~PluginManager();
82 
83     static std::string description(const std::string& name);
84     static std::string link(const std::string& name);
85     template <typename C>
registerPlugin(const PluginInfo & info)86     static bool registerPlugin(const PluginInfo& info)
87         { return get().template l_registerPlugin<C>(info); }
88     template <typename C>
registerPlugin(const StaticPluginInfo & info)89     static bool registerPlugin(const StaticPluginInfo& info)
90         { return get().template l_registerPlugin<C>(info); }
91     static bool loadPlugin(const std::string& pluginFilename);
92     static T *createObject(const std::string& objectType);
93     static StringList names();
94     static void setLog(LogPtr& log);
95     static void loadAll();
96     static bool loadDynamic(const std::string& driverName);
97     static PluginManager<T>& get();
98     static StageExtensions& extensions();
99 
100 private:
101     PluginManager();
102 
103     std::string getPath(const std::string& driver);
104     void shutdown();
105     bool loadByPath(const std::string & path);
106     bool l_loadDynamic(const std::string& driverName);
107     DynamicLibrary *libraryLoaded(const std::string& path);
108     DynamicLibrary *loadLibrary(const std::string& path);
109     T *l_createObject(const std::string& objectType);
110     template <class C>
l_registerPlugin(const PluginInfo & pi)111     bool l_registerPlugin(const PluginInfo& pi)
112     {
113         auto f = [&]()
114         {
115             T *t = dynamic_cast<T *>(new C);
116             return t;
117         };
118         Info info {pi.name, pi.link, pi.description, f};
119         std::lock_guard<std::mutex> lock(m_pluginMutex);
120         m_plugins.insert(std::make_pair(pi.name, info));
121         return true;
122     }
123     template <class C>
l_registerPlugin(const StaticPluginInfo & pi)124     bool l_registerPlugin(const StaticPluginInfo& pi)
125     {
126         l_registerPlugin<C>((const PluginInfo&)pi);
127         m_extensions.set(pi.name, pi.extensions);
128         return true;
129     }
130 
131     bool l_loadPlugin(const std::string& pluginFilename);
132     StringList l_names();
133     std::string l_description(const std::string& name);
134     std::string l_link(const std::string& name);
135     void l_loadAll();
136 
137     DynamicLibraryMap m_dynamicLibraryMap;
138     RegistrationInfoMap m_plugins;
139     std::mutex m_pluginMutex;
140     std::mutex m_libMutex;
141     LogPtr m_log;
142     StageExtensions m_extensions;
143 };
144 
145 } // namespace pdal
146 
147