1 /******************************************************************************
2 
3   This source file is part of the Avogadro project.
4 
5   Copyright 2012 Kitware, Inc.
6 
7   This source code is released under the New BSD License, (the "License").
8 
9   Unless required by applicable law or agreed to in writing, software
10   distributed under the License is distributed on an "AS IS" BASIS,
11   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   See the License for the specific language governing permissions and
13   limitations under the License.
14 
15 ******************************************************************************/
16 
17 #include "pluginmanager.h"
18 
19 #include "molequeueconfig.h"
20 
21 #include <molequeue/servercore/connectionlistenerfactory.h>
22 
23 #include <QtCore/QCoreApplication>
24 #include <QtCore/QMutex>
25 #include <QtCore/QPluginLoader>
26 #include <QtCore/QDir>
27 #include <QtCore/QFileInfo>
28 
29 #include <QtCore/QDebug>
30 
31 namespace MoleQueue
32 {
33 
34 namespace
35 {
36 // Compiler initializes this static pointer to 0.
37 static PluginManager *pluginManagerInstance;
38 }
39 
PluginManager(QObject * p)40 PluginManager::PluginManager(QObject *p) : QObject(p)
41 {
42   QString libDir(MoleQueue_LIB_DIR);
43   // http://doc.qt.digia.com/qt/deployment-plugins.html#debugging-plugins
44   bool debugPlugins = !qgetenv("QT_DEBUG_PLUGINS").isEmpty();
45   QDir baseDir(QCoreApplication::applicationDirPath() + "/..");
46   m_relativeToApp = "/../" + libDir + "/molequeue/plugins";
47 #ifdef __APPLE__
48   // But if NOT running from the installed bundle on the Mac, the plugins are
49   // relative to the build directory instead:
50   if (!QFileInfo(baseDir.absolutePath() + "/Resources/qt.conf").exists()) {
51     QDir buildDir(QCoreApplication::applicationDirPath() + "/../../../..");
52     baseDir = buildDir;
53     if (debugPlugins)
54       qDebug() << "  using buildDir:" << buildDir.absolutePath();
55   }
56 #endif
57 
58 // For multi configuration types add correct one to search path.
59 #ifdef MULTI_CONFIG_BUILD
60   // First extract the build type (the name of the application dir).
61   QDir appDir(QCoreApplication::applicationDirPath());
62   QString buildType = appDir.dirName();
63 
64   QDir condir(QCoreApplication::applicationDirPath()
65            + "/../../" + libDir + "/molequeue/plugins/" + buildType);
66   m_pluginDirs.append(condir.absolutePath());
67 #endif
68   // If the environment variable is set, use that as the base directory.
69   QByteArray pluginDir = qgetenv("MOLEQUEUE_PLUGIN_DIR");
70   if (!pluginDir.isEmpty())
71     baseDir.setPath(pluginDir);
72   if (debugPlugins)
73     qDebug() << "  baseDir:" << baseDir.absolutePath();
74   QDir pluginsDir(baseDir.absolutePath() + "/" + libDir + "/molequeue/plugins");
75   m_pluginDirs.append(pluginsDir.absolutePath());
76   if (debugPlugins) {
77     qDebug() << "  pluginsDir:" << pluginsDir.absolutePath();
78     int count = 0;
79     foreach(const QString &pluginPath, pluginsDir.entryList(QDir::Files)) {
80       ++count;
81       qDebug() << " " << pluginsDir.absolutePath() + "/" + pluginPath;
82     }
83 
84     if (count > 0)
85       qDebug() << " " << count << "files found in" << pluginsDir.absolutePath();
86     else
87       qDebug() << "  no plugin files found in" << pluginsDir.absolutePath();
88   }
89 }
90 
~PluginManager()91 PluginManager::~PluginManager()
92 {
93 }
94 
instance()95 PluginManager * PluginManager::instance()
96 {
97   static QMutex mutex;
98   if (!pluginManagerInstance) {
99     mutex.lock();
100     if (!pluginManagerInstance)
101       pluginManagerInstance = new PluginManager(QCoreApplication::instance());
102     mutex.unlock();
103   }
104   return pluginManagerInstance;
105 }
106 
load()107 void PluginManager::load()
108 {
109   foreach(const QString &dir, m_pluginDirs)
110     load(dir);
111 }
112 
load(const QString & path)113 void PluginManager::load(const QString &path)
114 {
115   QDir dir(path);
116   qDebug() << "Checking for plugins in" << path;
117   qDebug() << dir.entryList(QDir::Files);
118   foreach(const QString &pluginPath, dir.entryList(QDir::Files)) {
119     QPluginLoader pluginLoader(dir.absolutePath() + QDir::separator() + pluginPath);
120 
121     if (pluginLoader.isLoaded()) {
122       qDebug() << "Plugin already loaded: " << pluginLoader.fileName();
123       continue;
124     }
125 
126     QObject *pluginInstance = pluginLoader.instance();
127 
128     // Check if the plugin loaded correctly. Keep debug output for now, should
129     // go away once we have verified this (or added to a logger).
130     if (!pluginInstance) {
131       qDebug() << "Failed to load" << pluginPath << "error"
132                << pluginLoader.errorString();
133     }
134     else {
135       qDebug() << "Loaded" << pluginPath << "->";
136       pluginInstance->dumpObjectInfo();
137     }
138 
139     // Now attempt to cast to known factory types, and make it available.
140     ConnectionListenerFactory *connectionListenerFactory =
141       qobject_cast<ConnectionListenerFactory *>(pluginInstance);
142     if (connectionListenerFactory &&
143         !m_connectionListenerFactories.contains(connectionListenerFactory))
144       m_connectionListenerFactories.append(connectionListenerFactory);
145   }
146 }
147 
connectionListenerFactories() const148 QList<ConnectionListenerFactory *> PluginManager::connectionListenerFactories() const
149 {
150   return m_connectionListenerFactories;
151 }
152 
153 } // End MoleQueue namespace
154