1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). |
4 | ** Contact: http://www.qt-project.org/legal |
5 | ** |
6 | ** This file is part of the QtSystems module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL21$ |
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 The Qt Company. For licensing terms |
14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free |
20 | ** Software Foundation and appearing in the file LICENSE.LGPLv21 and |
21 | ** LICENSE.LGPLv3 included in the packaging of this file. Please review the |
22 | ** following information to ensure the GNU Lesser General Public License |
23 | ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and |
24 | ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
25 | ** |
26 | ** As a special exception, The Qt Company gives you certain additional |
27 | ** rights. These rights are described in The Qt Company LGPL Exception |
28 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
29 | ** |
30 | ** $QT_END_LICENSE$ |
31 | ** |
32 | ****************************************************************************/ |
33 | |
34 | #include <QRegExp> |
35 | #include <QStringList> |
36 | #include <QDebug> |
37 | #ifndef QT_NO_DATASTREAM |
38 | #include <qdatastream.h> |
39 | #endif |
40 | |
41 | #include "qservicefilter.h" |
42 | |
43 | QT_BEGIN_NAMESPACE |
44 | |
45 | class QServiceFilterPrivate |
46 | { |
47 | public: |
48 | QString interface; |
49 | QString service; |
50 | int majorVersion; |
51 | int minorVersion; |
52 | QServiceFilter::VersionMatchRule matchingRule; |
53 | QHash<QString,QString> customAttributes; |
54 | QStringList capabilities; |
55 | QServiceFilter::CapabilityMatchRule capMatchingRule; |
56 | }; |
57 | |
58 | |
59 | /*! |
60 | \class QServiceFilter |
61 | |
62 | \ingroup servicefw |
63 | \inmodule QtServiceFramework |
64 | \brief The QServiceFilter class defines criteria for defining a sub-set of |
65 | all available services. |
66 | |
67 | A QServiceFilter can be used to constrain the number of services when searching |
68 | for services. Only those services that match all filter criteria are returned |
69 | by \l QServiceManager::findInterfaces(). |
70 | |
71 | |
72 | \sa QServiceInterfaceDescriptor, QServiceManager |
73 | */ |
74 | |
75 | /*! |
76 | \enum QServiceFilter::VersionMatchRule |
77 | |
78 | This enum describes how interface version matching is performed. |
79 | |
80 | \value ExactVersionMatch The filter matches any interface implementation that implements |
81 | the exact version provided. |
82 | \value MinimumVersionMatch The filter matches any interface implementation that implements |
83 | either the given major/minor version or any subsequent version. |
84 | */ |
85 | |
86 | /*! |
87 | \enum QServiceFilter::CapabilityMatchRule |
88 | |
89 | This enum describes the capability/permission matching rules. Some platforms restrict what services clients |
90 | can access using "capabilities" or permissions. Services with more capabilities require |
91 | more privileged clients. Platforms without capabilities may ignore this type of matching |
92 | rule as the default behavior is to ignore any capability restrictions. |
93 | |
94 | This is a brief example. Assuming that the system knows the services S1 - S6 which require capabilities as stated below: |
95 | \table |
96 | \header \li Service \li Required capabilities |
97 | \row \li S1 \li \{\} |
98 | \row \li S2 \li \{A\} |
99 | \row \li S3 \li \{A,B\} |
100 | \row \li S4 \li \{A,B,C,D\} |
101 | \row \li S5 \li \{A,D\} |
102 | \row \li S6 \li \{F\} |
103 | \endtable |
104 | |
105 | The matching rules would apply as follows: |
106 | |
107 | \table |
108 | \header \li Matching rule \li Filter's capabilities \li Matching services |
109 | \row \li MatchLoadable \li \{\} \li S1 |
110 | \row \li MatchLoadable \li \{A\} \li S1, S2 |
111 | \row \li MatchLoadable \li \{A,B,C\} \li S1, S2, S3 |
112 | \row \li MatchMinimum \li \{\} \li S1, S2, S3, S4, S5, S6 |
113 | \row \li MatchMinimum \li \{A\} \li S2, S3, S4, S5 |
114 | \row \li MatchMinimum \li \{A,B,C\} \li S4 |
115 | \endtable |
116 | |
117 | \value MatchMinimum The filter matches any service that requires at least the given |
118 | filter capabilities. This may mean that the returned services |
119 | may require more capabilities than the specified ones. |
120 | Such a search is equivalent to a wildcard match if the passed filter's capability list is empty. In mathematical set notation |
121 | this rule is equivalent to Cap\sub{(Filter)} \\ Cap\sub{(Service)} = {}. This is the default matching rule. |
122 | \value MatchLoadable The filter matches any service that could be loaded by the client. |
123 | Using this matching rule guarantees that the returned services do not |
124 | require more capabilites than specified by this rule. It includes services |
125 | with no capability requirements. If this rule |
126 | is provided alongside an empty capability search list the returned |
127 | services do not require any capabilities and thus can be accessed |
128 | by any client. The equivalent set notation is Cap\sub{(Service)} \\ Cap\sub{(Filter)} = {}. |
129 | */ |
130 | |
131 | /*! |
132 | Creates a new filter object that matches all service implementations. |
133 | */ |
134 | QServiceFilter::QServiceFilter() |
135 | { |
136 | d = new QServiceFilterPrivate(); |
137 | d->majorVersion = -1; |
138 | d->minorVersion = -1; |
139 | d->matchingRule = QServiceFilter::MinimumVersionMatch; |
140 | d->capMatchingRule = QServiceFilter::MatchMinimum; |
141 | } |
142 | |
143 | /*! |
144 | Creates a copy of QServiceFilter object contained in \a other. |
145 | */ |
146 | QServiceFilter::QServiceFilter(const QServiceFilter& other) |
147 | { |
148 | d = new QServiceFilterPrivate(); |
149 | (*this) = other; |
150 | } |
151 | |
152 | /*! |
153 | \fn QServiceFilter::QServiceFilter(const QString& interfaceName, const QString& version, QServiceFilter::VersionMatchRule rule) |
154 | |
155 | Creates a new filter object that matches all service |
156 | implementations implementing \a interfaceName that match the specified |
157 | \a version using the given \a rule. |
158 | */ |
159 | QServiceFilter::QServiceFilter(const QString& interfaceName, const QString& version, QServiceFilter::VersionMatchRule rule) |
160 | { |
161 | d = new QServiceFilterPrivate(); |
162 | d->majorVersion = -1; |
163 | d->minorVersion = -1; |
164 | d->matchingRule = QServiceFilter::MinimumVersionMatch; |
165 | d->capMatchingRule = QServiceFilter::MatchMinimum; |
166 | setInterface(interfaceName, version, rule); |
167 | } |
168 | |
169 | /*! |
170 | Destroys this instance of QServiceFilter. |
171 | */ |
172 | QServiceFilter::~QServiceFilter() |
173 | { |
174 | delete d; |
175 | } |
176 | |
177 | /*! |
178 | \fn QServiceFilter& QServiceFilter::operator=(const QServiceFilter& other) |
179 | |
180 | Copies the content of the QServiceFilter object contained in |
181 | \a other into this one. |
182 | */ |
183 | QServiceFilter& QServiceFilter::operator=(const QServiceFilter& other) |
184 | { |
185 | if (&other == this) |
186 | return *this; |
187 | |
188 | d->interface = other.d->interface; |
189 | d->service = other.d->service; |
190 | d->majorVersion = other.d->majorVersion; |
191 | d->minorVersion = other.d->minorVersion; |
192 | d->matchingRule = other.d->matchingRule; |
193 | d->customAttributes = other.d->customAttributes; |
194 | d->capabilities = other.d->capabilities; |
195 | d->capMatchingRule = other.d->capMatchingRule; |
196 | |
197 | return *this; |
198 | } |
199 | |
200 | /*! |
201 | \fn void QServiceFilter::setServiceName(const QString& serviceName) |
202 | |
203 | The filter only matches implementations which are provided by the service |
204 | specified by \a serviceName. |
205 | |
206 | If the \a serviceName is empty the filter matches any service. |
207 | */ |
208 | void QServiceFilter::setServiceName(const QString& serviceName) |
209 | { |
210 | d->service = serviceName; |
211 | } |
212 | |
213 | /*! |
214 | \fn void QServiceFilter::setInterface(const QString &interfaceName, const QString& version, QServiceFilter::VersionMatchRule rule) |
215 | |
216 | Sets the filter to match any interface implementation that implements |
217 | \a interfaceName with version \a version. The version is matched |
218 | according to the given \a rule. If \a version is not set, the filter matches any version of the |
219 | interface implementation. |
220 | |
221 | This method does nothing if \a version is not a valid version string or |
222 | if \a interfaceName is empty. |
223 | |
224 | A valid version string has the format x.y whereby x and y are positive integer |
225 | numbers. |
226 | */ |
227 | void QServiceFilter::setInterface(const QString &interfaceName, const QString& version, QServiceFilter::VersionMatchRule rule) |
228 | { |
229 | //unset interface name |
230 | if (interfaceName.isEmpty() && version.isEmpty()) |
231 | { |
232 | d->interface = interfaceName; |
233 | d->majorVersion = d->minorVersion = -1; |
234 | d->matchingRule = rule; |
235 | return; |
236 | } |
237 | |
238 | if (interfaceName.isEmpty()) { |
239 | qWarning() << "Empty interface name. Ignoring filter details" ; |
240 | return; |
241 | } |
242 | |
243 | if (version.isEmpty()) { |
244 | d->majorVersion = d->minorVersion = -1; |
245 | d->matchingRule = rule; |
246 | d->interface = interfaceName; |
247 | return; |
248 | } |
249 | |
250 | // Match x.y as version format. |
251 | // This differs from regex in servicemetadata in that 0.x versions are |
252 | // accepted for the search filter. |
253 | QRegExp rx(QLatin1String("^(0+|[1-9][0-9]*)\\.(0+|[1-9][0-9]*)$" )); |
254 | int pos = rx.indexIn(str: version); |
255 | QStringList list = rx.capturedTexts(); |
256 | bool success = false; |
257 | int temp_major = -1; |
258 | int temp_minor = -1; |
259 | if (pos == 0 && list.count() == 3 |
260 | && rx.matchedLength() == version.length() ) |
261 | { |
262 | temp_major = list[1].toInt(ok: &success); |
263 | if ( success ) { |
264 | temp_minor = list[2].toInt(ok: &success); |
265 | } |
266 | } |
267 | |
268 | if (success) { |
269 | d->majorVersion = temp_major; |
270 | d->minorVersion = temp_minor; |
271 | d->interface = interfaceName; |
272 | d->matchingRule = rule; |
273 | } else { |
274 | qWarning() << "Invalid version tag" << version << ". Ignoring filter details." ; |
275 | } |
276 | } |
277 | |
278 | /*! |
279 | \fn QString QServiceFilter::serviceName() const |
280 | |
281 | Returns the service name for this filter. |
282 | |
283 | \sa setServiceName() |
284 | */ |
285 | QString QServiceFilter::serviceName() const |
286 | { |
287 | return d->service; |
288 | } |
289 | |
290 | /*! |
291 | \fn QString QServiceFilter::interfaceName() const |
292 | |
293 | Returns the interface name for this filter. |
294 | |
295 | \sa setInterface() |
296 | */ |
297 | QString QServiceFilter::interfaceName() const |
298 | { |
299 | return d->interface; |
300 | } |
301 | |
302 | /*! |
303 | \fn int QServiceFilter::majorVersion() const |
304 | |
305 | Returns the major interface version for this filter. |
306 | |
307 | \sa setInterface() |
308 | */ |
309 | int QServiceFilter::majorVersion() const |
310 | { |
311 | return d->majorVersion; |
312 | } |
313 | |
314 | /*! |
315 | \fn int QServiceFilter::minorVersion() const |
316 | |
317 | Returns the minor interface version for this filter. |
318 | |
319 | \sa setInterface() |
320 | */ |
321 | int QServiceFilter::minorVersion() const |
322 | { |
323 | return d->minorVersion; |
324 | } |
325 | |
326 | /*! |
327 | \fn void QServiceFilter::setCustomAttribute(const QString& key, const QString& value) |
328 | |
329 | The filter only matches implementations which have the custom attribute |
330 | \a key with the given \a value. Such constraints are specified via the |
331 | \e{<customproperty>} tag within the service xml. |
332 | |
333 | \sa customAttribute(), clearCustomAttribute() |
334 | */ |
335 | void QServiceFilter::setCustomAttribute(const QString& key, const QString& value) |
336 | { |
337 | d->customAttributes.insert(akey: key, avalue: value); |
338 | } |
339 | |
340 | /*! |
341 | \fn QString QServiceFilter::customAttribute(const QString& key) const |
342 | |
343 | Returns the value for the custom attribute \a key; otherwise |
344 | returns a null string. |
345 | |
346 | \sa setCustomAttribute(), clearCustomAttribute() |
347 | */ |
348 | QString QServiceFilter::customAttribute(const QString& key) const |
349 | { |
350 | return d->customAttributes.value(akey: key); |
351 | } |
352 | |
353 | /*! |
354 | \fn void QServiceFilter::clearCustomAttribute(const QString &key) |
355 | |
356 | Clears the custom attribute \a key from the filter's set of constraints. |
357 | If \a key is empty all custom attributes are cleared. |
358 | |
359 | \sa setCustomAttribute() |
360 | */ |
361 | void QServiceFilter::clearCustomAttribute(const QString &key) |
362 | { |
363 | if (key.isEmpty()) |
364 | d->customAttributes.clear(); |
365 | else |
366 | d->customAttributes.remove(akey: key); |
367 | } |
368 | |
369 | /*! |
370 | \fn QServiceFilter::VersionMatchRule QServiceFilter::versionMatchRule() const |
371 | |
372 | Returns the version match rule for this filter. |
373 | |
374 | \sa setInterface() |
375 | */ |
376 | QServiceFilter::VersionMatchRule QServiceFilter::versionMatchRule() const |
377 | { |
378 | return d->matchingRule; |
379 | } |
380 | |
381 | /*! |
382 | \fn QList<QString> QServiceFilter::customAttributes() const |
383 | |
384 | Returns the list of custom keys which have been added to the filter. |
385 | */ |
386 | QStringList QServiceFilter::customAttributes() const |
387 | { |
388 | return d->customAttributes.keys(); |
389 | } |
390 | |
391 | /*! |
392 | \fn void QServiceFilter::setCapabilities(QServiceFilter::CapabilityMatchRule rule, const QStringList& capabilities ) |
393 | |
394 | Sets the list of \a capabilities which are used to constrain |
395 | searches for services. The capabilities are matched according |
396 | to the given \a rule. |
397 | |
398 | \sa capabilities() |
399 | */ |
400 | void QServiceFilter::setCapabilities(QServiceFilter::CapabilityMatchRule rule, const QStringList& capabilities ) |
401 | { |
402 | d->capMatchingRule = rule; |
403 | d->capabilities = capabilities; |
404 | } |
405 | |
406 | /*! |
407 | \fn QStringList QServiceFilter::capabilities() const |
408 | |
409 | Returns the list of capabilities which are used to limit services searches. |
410 | |
411 | The filter matches any services that requires the given or less |
412 | capabilities and thus enabling clients to query for services |
413 | for which they have the required capabilties. |
414 | |
415 | \sa setCapabilities(), capabilityMatchRule() |
416 | */ |
417 | QStringList QServiceFilter::capabilities() const |
418 | { |
419 | return d->capabilities; |
420 | } |
421 | |
422 | /*! |
423 | Returns the capability matching rule for this filter. |
424 | |
425 | \sa setCapabilities(), capabilities() |
426 | */ |
427 | QServiceFilter::CapabilityMatchRule QServiceFilter::capabilityMatchRule() const |
428 | { |
429 | return d->capMatchingRule; |
430 | } |
431 | |
432 | #ifndef QT_NO_DATASTREAM |
433 | /*! |
434 | \fn QDataStream &operator<<(QDataStream &out, const QServiceFilter &sf) |
435 | \relates QServiceFilter |
436 | |
437 | Writes service filter \a sf to the stream \a out and returns a reference |
438 | to the stream. |
439 | */ |
440 | QDataStream &operator<<(QDataStream &out, const QServiceFilter &sf) |
441 | { |
442 | const quint32 magicNumber = 0x78AFAFA; |
443 | const qint32 mj = sf.d->majorVersion; |
444 | const qint32 mn = sf.d->minorVersion; |
445 | const qint8 versionrule = (qint32) sf.d->matchingRule; |
446 | const qint8 caprule = (qint8) sf.d->capMatchingRule; |
447 | const quint16 majorVersion = 1; |
448 | const quint16 minorVersion = 0; |
449 | |
450 | out << magicNumber |
451 | << majorVersion |
452 | << minorVersion |
453 | << sf.d->interface |
454 | << sf.d->service |
455 | << mj |
456 | << mn |
457 | << versionrule |
458 | << sf.d->customAttributes |
459 | << caprule |
460 | << sf.d->capabilities; |
461 | return out; |
462 | } |
463 | |
464 | /*! |
465 | \fn QDataStream &operator>>(QDataStream &in, QServiceFilter &sf) |
466 | \relates QServiceFilter |
467 | |
468 | Reads a service filter into \a sf from the stream \a in and returns a |
469 | reference to the stream. |
470 | */ |
471 | QDataStream &operator>>(QDataStream &in, QServiceFilter &sf) |
472 | { |
473 | const quint32 magicNumber = 0x78AFAFA; |
474 | qint32 mj, mn; |
475 | qint8 versionrule, caprule; |
476 | |
477 | quint32 storedMagicNumber; |
478 | in >> storedMagicNumber; |
479 | if (storedMagicNumber != magicNumber) { |
480 | qWarning() << Q_FUNC_INFO << "Datastream doesn't provide serialized QServiceFilter" ; |
481 | return in; |
482 | } |
483 | |
484 | const quint16 currentMajorVersion = 1; |
485 | quint16 majorVersion = 0; |
486 | quint16 minorVersion = 0; |
487 | |
488 | in >> majorVersion >> minorVersion; |
489 | if (majorVersion != currentMajorVersion) { |
490 | qWarning() << "Unknown serialization format for QServiceFilter." ; |
491 | return in; |
492 | } |
493 | //Allow all minor versions. |
494 | |
495 | in >> sf.d->interface |
496 | >> sf.d->service |
497 | >> mj |
498 | >> mn |
499 | >> versionrule |
500 | >> sf.d->customAttributes |
501 | >> caprule |
502 | >> sf.d->capabilities; |
503 | |
504 | sf.d->majorVersion = mj; |
505 | sf.d->minorVersion = mn; |
506 | sf.d->matchingRule = (QServiceFilter::VersionMatchRule) versionrule; |
507 | sf.d->capMatchingRule = (QServiceFilter::CapabilityMatchRule) caprule; |
508 | |
509 | return in; |
510 | } |
511 | #endif //QT_NO_DATASTREAM |
512 | |
513 | |
514 | QT_END_NAMESPACE |
515 | |
516 | |