1/*
2 * Copyright 2013 Christian Mollekopf <mollekopf@kolabsys.com>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License or (at your option) version 3 or any later version
8 * accepted by the membership of KDE e.V. (or its successor approved
9 * by the membership of KDE e.V.), which shall act as a proxy
10 * defined in Section 14 of version 3 of the license.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef MIGRATORBASE_H
23#define MIGRATORBASE_H
24
25#include <QtCore/QObject>
26#include <QFile>
27#include <kconfig.h>
28#include <KConfigGroup>
29
30class QFile;
31
32class NullableConfigGroup
33{
34public:
35 NullableConfigGroup()
36 {}
37
38 NullableConfigGroup(KConfigGroup grp): mConfigGroup(grp)
39 {}
40
41 KConfigGroup &configGroup()
42 {
43 return mConfigGroup;
44 }
45
46 template <typename T>
47 inline T readEntry(const QString &key, const T &aDefault) const
48 {
49 if (mConfigGroup.isValid()) {
50 return mConfigGroup.readEntry<T>(key, aDefault);
51 }
52 return aDefault;
53 }
54
55 template <typename T>
56 inline void writeEntry(const QString &key, const T &value)
57 {
58 if (mConfigGroup.isValid()) {
59 mConfigGroup.writeEntry<T>(key, value);
60 }
61 }
62private:
63 KConfigGroup mConfigGroup;
64};
65
66/**
67 * Base class for generic migration jobs in akonadi.
68 *
69 * MigrationJobs can be run standalone from commandline using a small wrapper application or using the
70 * Akonadi Migration Agent.
71 *
72 * Each migrator should assign a unique identifier for it's state (this identifier must never change).
73 *
74 * The work done by the migrator may be paused, and the migrator may persist it's state to resume migrations after a reboot.
75 *
76 * TODO: The migrator base ensures that no migrator can be run multiple times by locking it over dbus.
77 *
78 * The status is stored in the akonadi instance config directory, meaning the status is stored per akonadi instance.
79 * This is the only reason why this MigratorBase is currently specific to akonadi migration jobs.
80 */
81class MigratorBase : public QObject
82{
83 Q_OBJECT
84public:
85 /**
86 * Default constructor with default config and logfile
87 */
88 explicit MigratorBase(const QString &identifier, QObject *parent = 0);
89
90 /**
91 * Constructor that allows to inject a configfile and logfile.
92 *
93 * Pass and empty string to disable config and log.
94 */
95 explicit MigratorBase(const QString &identifier, const QString &configFile, const QString &logFile, QObject *parent = 0);
96
97 virtual ~MigratorBase();
98
99 QString identifier() const;
100
101 /**
102 * Translated, human readable display name of migrator.
103 */
104 virtual QString displayName() const;
105
106 /**
107 * Translated, human readable description of migrator.
108 */
109 virtual QString description() const;
110
111 /**
112 * Returns the filename of the logfile used by this migrator.
113 *
114 * Returns QString() if there is no logfile set.
115 */
116 QString logfile() const;
117
118 enum MigrationState {
119 None,
120 InProgress,
121 Paused,
122 Complete,
123 NeedsUpdate,
124 Aborted,
125 Failed
126 };
127
128 enum MessageType {
129 Success,
130 Skip,
131 Info,
132 Warning,
133 Error
134 };
135
136 /**
137 * Read migration state.
138 *
139 * @return MigrationState.
140 */
141 MigrationState migrationState() const;
142
143 /**
144 * Return false if this job cannot start (i.e. due to missing dependencies).
145 */
146 virtual bool canStart();
147
148 /**
149 * Mandatory updates that the Migration Agent should autostart should return true
150 */
151 virtual bool shouldAutostart() const;
152
153 /**
154 * Start migration.
155 *
156 * Implement startWork instead.
157 *
158 * Note that this will directly (blocking) call startWork().
159 */
160 void start();
161
162 /**
163 * Pause migration.
164 */
165 virtual void pause();
166
167 /**
168 * Resume migration.
169 */
170 virtual void resume();
171
172 /**
173 * Abort migration.
174 */
175 virtual void abort();
176
177 /**
178 * progress in percent
179 */
180 int progress() const;
181
182 /**
183 * Status
184 */
185 QString status() const;
186
187signals:
188 //Signal for state changes
189 void stateChanged(MigratorBase::MigrationState);
190
191 //Signal for log window
192 void message(MigratorBase::MessageType type, const QString &msg);
193
194 //Signal for progress bar
195 void progress(int progress);
196
197 //Signal for scheduling. The migrator has finished for some reason (success, failure, ...) and we can forget about it and move on.
198 void stoppedProcessing();
199
200protected:
201 /**
202 * Reimplement to start work.
203 */
204 virtual void startWork() = 0;
205
206 void setMigrationState(MigratorBase::MigrationState state);
207
208 void setProgress(int);
209
210private slots:
211 /**
212 * Logs a message, that appears in the logfile and potentially in a log window.
213 * Do not call this directly. Emit the message signal instead, which is connected to this slot.
214 */
215 void logMessage(MigratorBase::MessageType type, const QString &msg);
216
217private:
218 NullableConfigGroup config();
219 void saveState();
220 void loadState();
221
222 void setLogfile(const QString &);
223
224 const QString mIdentifier;
225 MigrationState mMigrationState;
226 QScopedPointer<QFile> mLogFile;
227 QScopedPointer<KConfig> mConfig;
228 int mProgress;
229};
230
231Q_DECLARE_METATYPE(MigratorBase::MigrationState)
232
233#endif // MIGRATORBASE_H
234