New: Add hotfixes plugin
[qtcontacts-tracker:jensg-contactsd.git] / plugins / hotfixes / plugin.cpp
1 /** This file is part of Contacts daemon
2  **
3  ** Copyright (c) 2010-2012 Nokia Corporation and/or its subsidiary(-ies).
4  **
5  ** Contact:  Nokia Corporation (info@qt.nokia.com)
6  **
7  ** GNU Lesser General Public License Usage
8  ** This file may be used under the terms of the GNU Lesser General Public License
9  ** version 2.1 as published by the Free Software Foundation and appearing in the
10  ** file LICENSE.LGPL included in the packaging of this file.  Please review the
11  ** following information to ensure the GNU Lesser General Public License version
12  ** 2.1 requirements will be met:
13  ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
14  **
15  ** In addition, as a special exception, Nokia gives you certain additional rights.
16  ** These rights are described in the Nokia Qt LGPL Exception version 1.1, included
17  ** in the file LGPL_EXCEPTION.txt in this package.
18  **
19  ** Other Usage
20  ** Alternatively, this file may be used in accordance with the terms and
21  ** conditions contained in a signed written agreement between you and Nokia.
22  **/
23
24 #include "base-plugin.h"
25 #include "debug.h"
26
27 #include "qmheartbeat.h"
28
29 namespace Contactsd {
30
31 using MeeGo::QmHeartbeat;
32
33 class HotFixesPlugin : public BasePlugin
34 {
35     Q_OBJECT
36
37 public:
38     HotFixesPlugin()
39         : m_heartbeat(0)
40         , m_timer(0)
41
42         , m_checkupQuery(QLatin1String
43           ("ASK {\n"
44            "  ?contact a nco:Contact\n"
45            "  GRAPH <urn:uuid:08070f5c-a334-4d19-a8b0-12a3071bfab9> {\n"
46            "    ?contact dc:date ?date\n"
47            "  }\n"
48            "  FILTER(!EXISTS { ?contact nie:contentLastModified ?date }\n"
49            "      && !EXISTS { ?contact nie:contentAccessed ?date }\n"
50            "      && !EXISTS { ?contact nie:contentCreated ?date })\n"
51            "}"), QSparqlQuery::AskStatement)
52
53         , m_cleanupQuery(QLatin1String
54           ("DELETE {\n"
55            "  ?contact nie:informationElementDate ?date ; dc:date ?date\n"
56            "} WHERE {\n"
57            "  SELECT ?contact ?date {\n"
58            "    GRAPH <urn:uuid:08070f5c-a334-4d19-a8b0-12a3071bfab9> {\n"
59            "      ?contact dc:date ?date\n"
60            "    }\n"
61            "    FILTER(!EXISTS { ?contact nie:contentLastModified ?date }\n"
62            "        && !EXISTS { ?contact nie:contentAccessed ?date }\n"
63            "        && !EXISTS { ?contact nie:contentCreated ?date })\n"
64            "  } LIMIT 500\n"
65            "}"), QSparqlQuery::DeleteStatement)
66     {
67     }
68
69     ~HotFixesPlugin()
70     {
71         if (m_heartbeat) {
72             m_heartbeat->close();
73         }
74     }
75
76     void init()
77     {
78         if (m_heartbeat) {
79             m_heartbeat->close();
80             m_heartbeat->deleteLater();
81             m_heartbeat = 0;
82         }
83
84         m_heartbeat = new QmHeartbeat(this);
85
86         if (m_heartbeat->open(QmHeartbeat::SignalNeeded)) {
87             connect(m_heartbeat, SIGNAL(wakeUp(QTime)), this, SLOT(onWakeUp()));
88         } else {
89             warning() << "hotfixes - Hearthbeat service not available, using fallback mechanism.";
90             m_heartbeat->deleteLater();
91             m_heartbeat = 0;
92
93             m_timer = new QTimer(this);
94             m_timer->setSingleShot(true);
95             connect(m_timer, SIGNAL(timeout()), this, SLOT(onWakeUp()));
96         }
97
98         scheduleWakeUp(0);
99     }
100
101     QMap<QString, QVariant> metaData()
102     {
103         MetaData data;
104         data[metaDataKeyName]    = QVariant(QString::fromLatin1("contacts-hotfixes"));
105         data[metaDataKeyVersion] = QVariant(QString::fromLatin1("1"));
106         data[metaDataKeyComment] = QVariant(QString::fromLatin1("Hotfixes for the contacts framework"));
107         return data;
108     }
109
110 private:
111     void scheduleWakeUp(unsigned short wakeupSlot = QmHeartbeat::WAKEUP_SLOT_10_HOURS)
112     {
113         debug() << "hotfixes - scheduling wakeup within" << wakeupSlot << "seconds";
114
115         if (m_heartbeat) {
116             m_heartbeat->wait(wakeupSlot,
117                               QmHeartbeat::WAKEUP_SLOT_10_HOURS,
118                               QmHeartbeat::DoNotWaitHeartbeat);
119         } else if (m_timer) {
120             // seems "wakeup slots" are just a delay in seconds
121             m_timer->setInterval(wakeupSlot * 1000);
122             m_timer->start();
123         }
124     }
125
126     bool runQuery(const QSparqlQuery &query, const char *slot)
127     {
128         QSparqlResult *const result = sparqlConnection().exec(query);
129
130         if (result->hasError()) {
131             warning() << "hotfixes - query failed:" << result->lastError().message();
132             result->deleteLater();
133             return false;
134         }
135
136         connect(result, SIGNAL(finished()), this, slot);
137         return true;
138     }
139
140     bool runCleanupQuery()
141     {
142         debug() << "hotfixes - running cleanup query";
143         return runQuery(m_cleanupQuery, SLOT(onCleanupQueryFinished()));
144     }
145
146     bool runCheckupQuery()
147     {
148         debug() << "hotfixes - running checkup query";
149         return runQuery(m_checkupQuery, SLOT(onCheckupQueryFinished()));
150     }
151
152 private slots:
153     void onWakeUp()
154     {
155         if (not runCleanupQuery()) {
156             scheduleWakeUp();
157         }
158     }
159
160     void onCleanupQueryFinished()
161     {
162         sender()->deleteLater();
163
164         if (not runCheckupQuery()) {
165             scheduleWakeUp();
166         }
167     }
168
169     void onCheckupQueryFinished()
170     {
171         QSparqlResult *const result = qobject_cast<QSparqlResult *>(sender());
172         bool cleanupNeeded = false;
173
174         while(result->next()) {
175             cleanupNeeded = result->value(0).toBool();
176         }
177
178         result->deleteLater();
179
180         scheduleWakeUp(cleanupNeeded ? QmHeartbeat::WAKEUP_SLOT_30_SEC
181                                      : QmHeartbeat::WAKEUP_SLOT_10_HOURS);
182     }
183
184
185 private:
186     QmHeartbeat *m_heartbeat;
187     QTimer *m_timer;
188
189     QSparqlQuery m_checkupQuery;
190     QSparqlQuery m_cleanupQuery;
191 };
192
193 } // namespace Contactsd
194
195 Q_EXPORT_PLUGIN2(garbagecollectorplugin, Contactsd::HotFixesPlugin)
196
197 #include "plugin.moc"