1 /****************************************************************************************
2  * Copyright (c) 2014 Ralf Engels <ralf-engels@gmx.de>                                  *
3  *                                                                                      *
4  * This program 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 Software        *
6  * Foundation; either version 2 of the License, or (at your option) any later           *
7  * version.                                                                             *
8  *                                                                                      *
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
11  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
12  *                                                                                      *
13  * You should have received a copy of the GNU General Public License along with         *
14  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
15  ****************************************************************************************/
16 
17 #define DEBUG_PREFIX "StorageManager"
18 
19 #include "StorageManager.h"
20 
21 #include <core/storage/SqlStorage.h>
22 #include <core/storage/StorageFactory.h>
23 
24 #include <core/support/Amarok.h>
25 #include <core/support/Debug.h>
26 
27 #include <KConfigGroup>
28 #include <KLocalizedString>
29 
30 /** A SqlStorage that doesn't do anything.
31  *
32  *  An object of this type is used whenever we couldn't
33  *  load a better SqlStorage.
34  *
35  *  The reason is that plugins don't have to check for
36  *  a null pointer as SqlStorage every time.
37  */
38 class EmptySqlStorage : public SqlStorage
39 {
40 public:
EmptySqlStorage()41     EmptySqlStorage() {}
~EmptySqlStorage()42     ~EmptySqlStorage() override {}
43 
sqlDatabasePriority() const44     virtual int sqlDatabasePriority() const
45     { return 10; }
46 
type() const47     virtual QString type() const { return QStringLiteral("Empty"); }
48 
escape(const QString & text) const49     QString escape( const QString &text) const override { return text; }
50 
query(const QString &)51     QStringList query( const QString &) override { return QStringList(); }
insert(const QString &,const QString &)52     int insert( const QString &, const QString &) override { return 0; }
53 
boolTrue() const54     QString boolTrue() const override { return QString(); }
boolFalse() const55     QString boolFalse() const override { return QString(); }
56 
idType() const57     QString idType() const override { return QString(); }
textColumnType(int) const58     QString textColumnType( int ) const override { return QString(); }
exactTextColumnType(int) const59     QString exactTextColumnType( int ) const override { return QString(); }
60 
exactIndexableTextColumnType(int) const61     QString exactIndexableTextColumnType( int ) const override { return QString(); }
longTextColumnType() const62     QString longTextColumnType() const override { return QString(); }
randomFunc() const63     QString randomFunc() const override { return QString(); }
64 
getLastErrors() const65     QStringList getLastErrors() const override { return QStringList(); }
66 
67     /** Clears the list of the last errors. */
clearLastErrors()68     void clearLastErrors() override { }
69 };
70 
71 
72 struct StorageManager::Private
73 {
74     QSharedPointer<SqlStorage> sqlDatabase;
75 
76     /** A list that collects errors from database plugins
77      *
78      *  StoragePlugin factories can report errors that
79      *  prevent the storage from even being created.
80      *
81      *  This list collects them.
82      */
83     QStringList errorList;
84 };
85 
86 StorageManager *StorageManager::s_instance = nullptr;
87 
88 
89 StorageManager *
instance()90 StorageManager::instance()
91 {
92     if( !s_instance ) {
93         s_instance = new StorageManager();
94         s_instance->init();
95     }
96 
97     return s_instance;
98 }
99 
100 void
destroy()101 StorageManager::destroy()
102 {
103     if( s_instance ) {
104         delete s_instance;
105         s_instance = nullptr;
106     }
107 }
108 
StorageManager()109 StorageManager::StorageManager()
110     : QObject()
111     , d( new Private )
112 {
113     DEBUG_BLOCK
114 
115     setObjectName( QStringLiteral("StorageManager") );
116     qRegisterMetaType<SqlStorage *>( "SqlStorage*" );
117     d->sqlDatabase = QSharedPointer<SqlStorage>( new EmptySqlStorage );
118 }
119 
~StorageManager()120 StorageManager::~StorageManager()
121 {
122     DEBUG_BLOCK
123 
124     delete d;
125 }
126 
127 QSharedPointer<SqlStorage>
sqlStorage() const128 StorageManager::sqlStorage() const
129 {
130     return d->sqlDatabase;
131 }
132 
133 void
init()134 StorageManager::init()
135 {
136 }
137 
138 void
setFactories(const QList<QSharedPointer<Plugins::PluginFactory>> & factories)139 StorageManager::setFactories( const QList<QSharedPointer<Plugins::PluginFactory> > &factories )
140 {
141     for( const auto &pFactory : factories )
142     {
143         auto factory = qobject_cast<StorageFactory*>( pFactory );
144         if( !factory )
145             continue;
146 
147         connect( factory.data(), &StorageFactory::newStorage,
148                  this, &StorageManager::slotNewStorage );
149         connect( factory.data(), &StorageFactory::newError,
150                  this, &StorageManager::slotNewError );
151     }
152 }
153 
154 QStringList
getLastErrors() const155 StorageManager::getLastErrors() const
156 {
157     if( !d->errorList.isEmpty() )
158         return d->errorList;
159     if( d->sqlDatabase.dynamicCast<EmptySqlStorage>() )
160     {
161         QStringList list;
162         list << i18n( "The configured database plugin could not be loaded." );
163         return list;
164     }
165     return d->errorList;
166 }
167 
168 void
clearLastErrors()169 StorageManager::clearLastErrors()
170 {
171     d->errorList.clear();
172 }
173 
174 void
slotNewStorage(QSharedPointer<SqlStorage> newStorage)175 StorageManager::slotNewStorage( QSharedPointer<SqlStorage> newStorage )
176 {
177     DEBUG_BLOCK
178 
179     if( !newStorage )
180     {
181         warning() << "Warning, newStorage in slotNewStorage is 0";
182         return;
183     }
184 
185     if( d->sqlDatabase && !d->sqlDatabase.dynamicCast<EmptySqlStorage>() )
186     {
187         warning() << "Warning, newStorage when we already have a storage";
188         return; // once we have the database set we can't change it since
189         // plugins might have already created their tables in the old database
190         // or caching data from it.
191     }
192 
193     d->sqlDatabase = newStorage;
194 }
195 
196 void
slotNewError(const QStringList & errorMessageList)197 StorageManager::slotNewError( const QStringList &errorMessageList )
198 {
199     d->errorList << errorMessageList;
200 }
201 
202 
203