75652b0902f504defee17b2ea2d8f63f65e9ae7c
[profile/ivi/qtbase.git] / src / corelib / plugin / qfactoryloader.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qfactoryloader_p.h"
43
44 #ifndef QT_NO_LIBRARY
45 #include "qfactoryinterface.h"
46 #include "qmap.h"
47 #include <qdir.h>
48 #include <qdebug.h>
49 #include "qmutex.h"
50 #include "qplugin.h"
51 #include "qpluginloader.h"
52 #include "private/qobject_p.h"
53 #include "private/qcoreapplication_p.h"
54 #include "qjsondocument.h"
55 #include "qjsonvalue.h"
56 #include "qjsonobject.h"
57 #include "qjsonarray.h"
58
59 QT_BEGIN_NAMESPACE
60
61 Q_GLOBAL_STATIC(QList<QFactoryLoader *>, qt_factory_loaders)
62
63 Q_GLOBAL_STATIC_WITH_ARGS(QMutex, qt_factoryloader_mutex, (QMutex::Recursive))
64
65 class QFactoryLoaderPrivate : public QObjectPrivate
66 {
67     Q_DECLARE_PUBLIC(QFactoryLoader)
68 public:
69     QFactoryLoaderPrivate(){}
70     ~QFactoryLoaderPrivate();
71     mutable QMutex mutex;
72     QByteArray iid;
73     QList<QLibraryPrivate*> libraryList;
74     QMap<QString,QLibraryPrivate*> keyMap;
75     QStringList keyList;
76     QString suffix;
77     Qt::CaseSensitivity cs;
78     QStringList loadedPaths;
79
80     void unloadPath(const QString &path);
81 };
82
83 QFactoryLoaderPrivate::~QFactoryLoaderPrivate()
84 {
85     for (int i = 0; i < libraryList.count(); ++i) {
86         QLibraryPrivate *library = libraryList.at(i);
87         library->unload();
88         library->release();
89     }
90 }
91
92 QFactoryLoader::QFactoryLoader(const char *iid,
93                                const QString &suffix,
94                                Qt::CaseSensitivity cs)
95     : QObject(*new QFactoryLoaderPrivate)
96 {
97     moveToThread(QCoreApplicationPrivate::mainThread());
98     Q_D(QFactoryLoader);
99     d->iid = iid;
100     d->cs = cs;
101     d->suffix = suffix;
102
103
104     QMutexLocker locker(qt_factoryloader_mutex());
105     update();
106     qt_factory_loaders()->append(this);
107 }
108
109
110
111 void QFactoryLoader::update()
112 {
113 #ifdef QT_SHARED
114     Q_D(QFactoryLoader);
115     QStringList paths = QCoreApplication::libraryPaths();
116     for (int i = 0; i < paths.count(); ++i) {
117         const QString &pluginDir = paths.at(i);
118         // Already loaded, skip it...
119         if (d->loadedPaths.contains(pluginDir))
120             continue;
121         d->loadedPaths << pluginDir;
122
123         QString path = pluginDir + d->suffix;
124         if (!QDir(path).exists(QLatin1String(".")))
125             continue;
126
127         QStringList plugins = QDir(path).entryList(QDir::Files);
128         QLibraryPrivate *library = 0;
129         for (int j = 0; j < plugins.count(); ++j) {
130             QString fileName = QDir::cleanPath(path + QLatin1Char('/') + plugins.at(j));
131
132             if (qt_debug_component()) {
133                 qDebug() << "QFactoryLoader::QFactoryLoader() looking at" << fileName;
134             }
135             library = QLibraryPrivate::findOrCreate(QFileInfo(fileName).canonicalFilePath());
136             if (!library->isPlugin()) {
137                 if (qt_debug_component()) {
138                     qDebug() << library->errorString;
139                     qDebug() << "         not a plugin";
140                 }
141                 library->release();
142                 continue;
143             }
144
145             QStringList keys;
146             bool metaDataOk = false;
147
148             QString iid = library->metaData.value(QLatin1String("IID")).toString();
149             if (iid == QLatin1String(d->iid.constData(), d->iid.size())) {
150                 QJsonObject object = library->metaData.value(QLatin1String("MetaData")).toObject();
151                 metaDataOk = true;
152
153                 QJsonArray k = object.value(QLatin1String("Keys")).toArray();
154                 for (int i = 0; i < k.size(); ++i) {
155                     QString s = k.at(i).toString();
156                     keys += s;
157                 }
158             }
159             if (qt_debug_component())
160                 qDebug() << "Got keys from plugin meta data" << keys;
161
162
163             if (!metaDataOk) {
164                 library->release();
165                 continue;
166             }
167
168             d->libraryList += library;
169             for (int k = 0; k < keys.count(); ++k) {
170                 // first come first serve, unless the first
171                 // library was built with a future Qt version,
172                 // whereas the new one has a Qt version that fits
173                 // better
174                 QString key = keys.at(k);
175                 if (!d->cs)
176                     key = key.toLower();
177                 QLibraryPrivate *previous = d->keyMap.value(key);
178                 int prev_qt_version = 0;
179                 if (previous) {
180                     prev_qt_version = (int)previous->metaData.value(QLatin1String("version")).toDouble();
181                 }
182                 int qt_version = (int)library->metaData.value(QLatin1String("version")).toDouble();
183                 if (!previous || (prev_qt_version > QT_VERSION && qt_version <= QT_VERSION)) {
184                     d->keyMap[key] = library;
185                     d->keyList += keys.at(k);
186                 }
187             }
188         }
189     }
190 #else
191     Q_D(QFactoryLoader);
192     if (qt_debug_component()) {
193         qDebug() << "QFactoryLoader::QFactoryLoader() ignoring" << d->iid
194                  << "since plugins are disabled in static builds";
195     }
196 #endif
197 }
198
199 QFactoryLoader::~QFactoryLoader()
200 {
201     QMutexLocker locker(qt_factoryloader_mutex());
202     qt_factory_loaders()->removeAll(this);
203 }
204
205 QList<QJsonObject> QFactoryLoader::metaData() const
206 {
207     Q_D(const QFactoryLoader);
208     QMutexLocker locker(&d->mutex);
209     QList<QJsonObject> metaData;
210     for (int i = 0; i < d->libraryList.size(); ++i)
211         metaData.append(d->libraryList.at(i)->metaData);
212
213     QVector<QStaticPlugin> staticPlugins = QLibraryPrivate::staticPlugins();
214     for (int i = 0; i < staticPlugins.count(); ++i) {
215         const char *rawMetaData = staticPlugins.at(i).metaData();
216         QJsonObject object = QLibraryPrivate::fromRawMetaData(rawMetaData).object();
217         if (object.value(QLatin1String("IID")) != QLatin1String(d->iid.constData(), d->iid.size()))
218             continue;
219
220         metaData.append(object);
221     }
222     return metaData;
223 }
224
225 QObject *QFactoryLoader::instance(int index) const
226 {
227     Q_D(const QFactoryLoader);
228     if (index < 0)
229         return 0;
230
231     if (index < d->libraryList.size()) {
232         QLibraryPrivate *library = d->libraryList.at(index);
233         if (library->instance || library->loadPlugin()) {
234             if (!library->inst)
235                 library->inst = library->instance();
236             QObject *obj = library->inst.data();
237             if (obj) {
238                 if (!obj->parent())
239                     obj->moveToThread(QCoreApplicationPrivate::mainThread());
240                 return obj;
241             }
242         }
243         return 0;
244     }
245
246     index -= d->libraryList.size();
247     QVector<QStaticPlugin> staticPlugins = QLibraryPrivate::staticPlugins();
248     for (int i = 0; i < staticPlugins.count(); ++i) {
249         const char *rawMetaData = staticPlugins.at(i).metaData();
250         QJsonObject object = QLibraryPrivate::fromRawMetaData(rawMetaData).object();
251         if (object.value(QLatin1String("IID")) != QLatin1String(d->iid.constData(), d->iid.size()))
252             continue;
253
254         if (index == 0)
255             return staticPlugins.at(i).instance();
256         --index;
257     }
258
259     return 0;
260 }
261
262 #if defined(Q_OS_UNIX) && !defined (Q_OS_MAC)
263 QLibraryPrivate *QFactoryLoader::library(const QString &key) const
264 {
265     Q_D(const QFactoryLoader);
266     return d->keyMap.value(d->cs ? key : key.toLower());
267 }
268 #endif
269
270 void QFactoryLoader::refreshAll()
271 {
272     QMutexLocker locker(qt_factoryloader_mutex());
273     QList<QFactoryLoader *> *loaders = qt_factory_loaders();
274     for (QList<QFactoryLoader *>::const_iterator it = loaders->constBegin();
275          it != loaders->constEnd(); ++it) {
276         (*it)->update();
277     }
278 }
279
280 QMultiMap<int, QString> QFactoryLoader::keyMap() const
281 {
282     QMultiMap<int, QString> result;
283     const QString metaDataKey = QStringLiteral("MetaData");
284     const QString keysKey = QStringLiteral("Keys");
285     const QList<QJsonObject> metaDataList = metaData();
286     for (int i = 0; i < metaDataList.size(); ++i) {
287         const QJsonObject metaData = metaDataList.at(i).value(metaDataKey).toObject();
288         const QJsonArray keys = metaData.value(keysKey).toArray();
289         const int keyCount = keys.size();
290         for (int k = 0; k < keyCount; ++k)
291             result.insert(i, keys.at(k).toString());
292     }
293     return result;
294 }
295
296 int QFactoryLoader::indexOf(const QString &needle) const
297 {
298     const QString metaDataKey = QStringLiteral("MetaData");
299     const QString keysKey = QStringLiteral("Keys");
300     const QList<QJsonObject> metaDataList = metaData();
301     for (int i = 0; i < metaDataList.size(); ++i) {
302         const QJsonObject metaData = metaDataList.at(i).value(metaDataKey).toObject();
303         const QJsonArray keys = metaData.value(keysKey).toArray();
304         const int keyCount = keys.size();
305         for (int k = 0; k < keyCount; ++k) {
306             if (!keys.at(k).toString().compare(needle, Qt::CaseInsensitive))
307                 return i;
308         }
309     }
310     return -1;
311 }
312
313 QT_END_NAMESPACE
314
315 #endif // QT_NO_LIBRARY