ArnLib  4.0.x
Active Registry Network
ArnDepend.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010-2022 Michael Wiklund.
2 // All rights reserved.
3 // Contact: arnlib@wiklunden.se
4 //
5 // This file is part of the ArnLib - Active Registry Network.
6 // Parts of ArnLib depend on Qt and/or other libraries that have their own
7 // licenses. Usage of these other libraries is subject to their respective
8 // license agreements.
9 //
10 // GNU Lesser General Public License Usage
11 // This file may be used under the terms of the GNU Lesser General Public
12 // License version 2.1 as published by the Free Software Foundation and
13 // appearing in the file LICENSE_LGPL.txt included in the packaging of this
14 // file. In addition, as a special exception, you may use the rights described
15 // in the Nokia Qt LGPL Exception version 1.1, included in the file
16 // LGPL_EXCEPTION.txt in this package.
17 //
18 // GNU General Public License Usage
19 // Alternatively, this file may be used under the terms of the GNU General Public
20 // License version 3.0 as published by the Free Software Foundation and appearing
21 // in the file LICENSE_GPL.txt included in the packaging of this file.
22 //
23 // Other Usage
24 // Alternatively, this file may be used in accordance with the terms and conditions
25 // contained in a signed written agreement between you and Michael Wiklund.
26 //
27 // This program is distributed in the hope that it will be useful, but WITHOUT ANY
28 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
29 // PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
30 //
31 
32 #include "ArnInc/ArnDepend.hpp"
33 #include "private/ArnDepend_p.hpp"
34 #include "ArnInc/ArnM.hpp"
35 #include "ArnInc/ArnLib.hpp"
36 #include <QUuid>
37 #include <QTimer>
38 #include <QtAlgorithms>
39 #include <QDebug>
40 
41 const char* ArnDependPath = "//.sys/Depend/";
42 
43 
45 
46 ArnDependOfferPrivate::ArnDependOfferPrivate()
47 {
48 }
49 
50 
51 ArnDependOfferPrivate::~ArnDependOfferPrivate()
52 {
53 }
54 
55 
57  : QObject( parent)
58  , d_ptr( new ArnDependOfferPrivate)
59 {
60 }
61 
62 
63 ArnDependOffer::ArnDependOffer( ArnDependOfferPrivate& dd, QObject* parent)
64  : QObject( parent)
65  , d_ptr( &dd)
66 {
67 }
68 
69 
71 {
72  delete d_ptr;
73 }
74 
75 
76 void ArnDependOffer::advertise( const QString& serviceName)
77 {
78  Q_D(ArnDependOffer);
79 
80  d->_serviceName = serviceName;
81  QString basePath = QString( ArnDependPath) + serviceName + "/";
82 
83  d->_arnEchoPipeFB.setPipeMode().setMaster();
84  d->_arnStateName.setMaster();
85  d->_arnStateId.setMaster();
86  d->_arnEchoPipeFB.open( basePath + "echoPipe!");
87  d->_arnStateName.open( basePath + "stateName");
88  d->_arnStateId.open( basePath + "stateId");
89 
90  d->_arnEchoPipeFB = "{}";
91  d->_arnStateName = "Start";
92  d->_arnStateId = 0;
93 
94  connect( &d->_arnEchoPipeFB, SIGNAL(changed(QByteArray)), this, SLOT(requestReceived(QByteArray)));
95 }
96 
97 
98 void ArnDependOffer::setStateName( const QString& name)
99 {
100  Q_D(ArnDependOffer);
101 
102  d->_arnStateName = name;
103 }
104 
105 
107 {
108  Q_D(const ArnDependOffer);
109 
110  return d->_arnStateName.toString();
111 }
112 
113 
115 {
116  Q_D(ArnDependOffer);
117 
118  d->_arnStateId = id;
119 }
120 
121 
123 {
124  Q_D(const ArnDependOffer);
125 
126  return d->_arnStateId.toInt();
127 }
128 
129 
130 void ArnDependOffer::requestReceived( QByteArray req)
131 {
132  Q_D(ArnDependOffer);
133 
134  if (Arn::debugDepend) qDebug() << "DepOffer request: service=" << d->_serviceName << " req=" << req
135  << "itemId=" << d->_arnEchoPipeFB.itemId();
136  d->_arnEchoPipeFB = req;
137 }
138 
139 
140 
142 
143 
144 ArnDependPrivate::ArnDependPrivate()
145 {
146  QUuid uuid = QUuid::createUuid();
147  _uuid = uuid.toString().toLatin1(); // Don't change after this assign
148  _pipeRegx = ARN_RegExp( ARN_RegExp::escape( QString::fromLatin1( _uuid)));
149  _started = false;
150  _timerEchoRefresh = new QTimer;
151  _timerEchoRefresh->setInterval(2000);
152 }
153 
154 
155 ArnDependPrivate::~ArnDependPrivate()
156 {
157  qDeleteAll( _depTab);
158  delete _timerEchoRefresh;
159 }
160 
161 
162 void ArnDepend::init()
163 {
164  Q_D(ArnDepend);
165 
166  connect( d->_timerEchoRefresh, SIGNAL(timeout()), this, SLOT(echoRefresh()));
167 }
168 
169 
170 ArnDepend::ArnDepend( QObject* parent)
171  : QObject( parent)
172  , d_ptr( new ArnDependPrivate)
173 {
174  init();
175 }
176 
177 
178 ArnDepend::ArnDepend( ArnDependPrivate& dd, QObject* parent)
179  : QObject( parent)
180  , d_ptr( &dd)
181 {
182  init();
183 }
184 
185 
187 {
188  delete d_ptr;
189 }
190 
191 
192 ArnDepend::DepSlot* ArnDepend::setupDepSlot( const QString& serviceName)
193 {
194  Q_D(ArnDepend);
195 
196  QString basePath = QString( ArnDependPath) + serviceName + "/";
197  DepSlot* slot = new DepSlot;
198 
199  slot->serviceName = serviceName;
200  slot->arnEchoPipe.open( basePath + "echoPipe");
201  slot->arnStateName.open( basePath + "stateName");
202  slot->arnStateId.open( basePath + "stateId");
203 
204  slot->arnEchoPipe.setReference( slot);
205  slot->arnStateName.setReference( slot);
206  slot->arnStateId.setReference( slot);
207 
208  d->_depTab += slot;
209  return slot;
210 }
211 
212 
213 void ArnDepend::add( const QString& serviceName, const QString& stateName)
214 {
215  DepSlot* slot = setupDepSlot( serviceName);
216  slot->stateName = stateName;
217  slot->useStateCheck = true;
218 }
219 
220 
221 void ArnDepend::add( const QString& serviceName, int stateId)
222 {
223  DepSlot* slot = setupDepSlot( serviceName);
224  slot->stateId = stateId;
225  slot->useStateCheck = stateId >= 0;
226 }
227 
228 
229 void ArnDepend::setMonitorName( const QString& name)
230 {
231  Q_D(ArnDepend);
232 
233  d->_name = name;
234 }
235 
236 
238 {
239  Q_D(ArnDepend);
240 
241  if (d->_started) return; // Already started
242 
243  // Connect & check all depency slots
244  foreach( DepSlot* slot, d->_depTab) {
245  connect( &slot->arnEchoPipe, SIGNAL(changed(QByteArray)), this, SLOT(echoCheck(QByteArray)));
246  echoCheck("", slot);
247  }
248  d->_started = true;
249 }
250 
251 
252 void ArnDepend::echoRefresh()
253 {
254  Q_D(ArnDepend);
255 
256  // ArnM::errorLog( QString(tr("Lost echo, doing refresh for DependEchoCheck monitor=")) + d->_name,
257  // ArnError::Warning);
258  foreach( DepSlot* slot, d->_depTab) {
259  echoCheck("", slot);
260  }
261 }
262 
263 
264 void ArnDepend::echoCheck( const QByteArray& echo, DepSlot* slot)
265 {
266  Q_D(ArnDepend);
267 
268  d->_timerEchoRefresh->start(); // Keep checking until finished
269 
270  if (Arn::debugDepend) qDebug() << "echoCheck: monitorName=" << d->_name;
271  if (slot == arnNullptr) {
272  ArnPipe* arnPipe = qobject_cast<ArnPipe*>( sender());
273  if (arnPipe) slot = static_cast<DepSlot*>( arnPipe->reference());
274  }
275  if (slot == arnNullptr) {
276  ArnM::errorLog( QString(tr("Can't get slot for DependEchoCheck monitor=")) + d->_name,
278  return;
279  }
280  if (slot->isEchoOk) return; // Echo already ok, test just in case ...
281 
282  if (echo.isEmpty()) {
283  if (Arn::debugDepend) qDebug() << "echoCheck: Send request monitorName=" << d->_name << " req=" << d->_uuid;
284  slot->arnEchoPipe.setValueOverwrite( d->_uuid, d->_pipeRegx); // Dependency request
285  }
286  else if (echo == d->_uuid) { // Dependency echo ok
287  slot->isEchoOk = true;
288  disconnect( &slot->arnEchoPipe, SIGNAL(changed(QByteArray)), this, SLOT(echoCheck(QByteArray))); // Avoid more signals
289  if (slot->useStateCheck) { // Go on with state check
290  connect( &slot->arnStateId, SIGNAL(changed()), this, SLOT(stateCheck()));
291  connect( &slot->arnStateName, SIGNAL(changed()), this, SLOT(stateCheck()));
292  stateCheck( slot);
293  }
294  else { // This dependency is ok
295  doDepOk( slot);
296  }
297  }
298 }
299 
300 
301 void ArnDepend::stateCheck( DepSlot* slot)
302 {
303  Q_D(ArnDepend);
304 
305  if (slot == arnNullptr) {
306  ArnItem* arnItem = qobject_cast<ArnItem*>( sender());
307  if (arnItem) slot = static_cast<DepSlot*>( arnItem->reference());
308  }
309  if (slot == arnNullptr) {
310  ArnM::errorLog( QString(tr("Can't get slot for DependStateCheck monitor=")) + d->_name,
312  return;
313  }
314  if (slot->isStateOk) return; // State already ok
315 
316  if (!slot->stateName.isEmpty() && (slot->arnStateName.toString() == slot->stateName)) {
317  slot->isStateOk = true;
318  doDepOk( slot);
319  }
320  else if ((slot->stateId > 0) && (slot->arnStateId.toInt() >= slot->stateId)) {
321  slot->isStateOk = true;
322  doDepOk( slot);
323  }
324 }
325 
326 
327 void ArnDepend::doDepOk( DepSlot* slot)
328 {
329  Q_D(ArnDepend);
330 
331  if (Arn::debugDepend) qDebug() << "depOk monitorName=" << d->_name;
332  QMetaObject::invokeMethod( this,
333  "deleteSlot",
334  Qt::QueuedConnection, // Delete later
335  Q_ARG( void*, slot));
336 }
337 
338 
339 void ArnDepend::deleteSlot( void* slot_)
340 {
341  Q_D(ArnDepend);
342 
343  DepSlot* slot = reinterpret_cast<DepSlot*>( slot_);
344  if (Arn::debugDepend) qDebug() << "deleteSlot monitorName=" << d->_name;
345  if (!d->_depTab.removeOne( slot)) {
346  ArnM::errorLog( QString(tr("Can't get slot for delete Depend monitor=")) + d->_name,
348  return;
349  }
350  delete slot;
351 
352  if (d->_depTab.isEmpty()) { // All dependencys ok
353  d->_timerEchoRefresh->stop();
354  emit completed();
355  d->_started = false; // Ok to start again
356  }
357 }
QString stateName() const
Definition: ArnDepend.cpp:106
void add(const QString &serviceName, int stateId=-1)
Add a dependency for a service
Definition: ArnDepend.cpp:221
bool debugDepend
Definition: ArnLib.cpp:46
ArnDependOffer(QObject *parent=arnNullptr)
Definition: ArnDepend.cpp:56
void setStateId(int id)
Set the state of the service by an id number.
Definition: ArnDepend.cpp:114
void completed()
Signal emitted when all dependent services are available.
Class for advertising that a service is available.
Definition: ArnDepend.hpp:59
const char * ArnDependPath
Definition: ArnDepend.cpp:41
#define ARN_RegExp
Definition: ArnCompat.hpp:70
ArnDepend(QObject *parent=arnNullptr)
Definition: ArnDepend.cpp:170
void * reference() const
Get the stored external reference.
void setMonitorName(const QString &name)
Set an optional monitor name for debugging.
Definition: ArnDepend.cpp:229
Class for setting up dependencis to needed services.
Definition: ArnDepend.hpp:132
void setStateName(const QString &name)
Set the state of the service by a logic name.
Definition: ArnDepend.cpp:98
void advertise(const QString &serviceName)
Advertise an available service
Definition: ArnDepend.cpp:76
ArnItem specialized as a pipe.
Definition: ArnPipe.hpp:64
ArnDependSlot DepSlot
Definition: ArnDepend.hpp:138
static void errorLog(QString errText, ArnError err=ArnError::Undef, void *reference=arnNullptr)
Definition: ArnM.cpp:1025
int stateId() const
Definition: ArnDepend.cpp:122
Handle for an Arn Data Object.
Definition: ArnItem.hpp:72
void startMonitor()
Starting the dependency monitor.
Definition: ArnDepend.cpp:237