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 <qserviceframeworkglobal.h>
35#include <QTimer>
36#include "instancemanager_p.h"
37#include "qremoteserviceregisterentry_p.h"
38
39QT_BEGIN_NAMESPACE
40
41Q_GLOBAL_STATIC(InstanceManager, typeRegister);
42
43/*!
44 \internal
45
46 Returns the instance manager for the service process
47*/
48InstanceManager* InstanceManager::instance()
49{
50 return typeRegister();
51}
52
53InstanceManager::InstanceManager(QObject *parent)
54 : QObject(parent)
55{
56}
57
58InstanceManager::~InstanceManager()
59{
60 QList<QRemoteServiceRegister::Entry> allEntries = metaMap.keys();
61 while (!allEntries.isEmpty()) {
62 ServiceIdentDescriptor descr = metaMap.take(akey: allEntries.takeFirst());
63 if (descr.entryData->instanceType == QRemoteServiceRegister::GlobalInstance) {
64 if (descr.globalInstance)
65 descr.globalInstance->deleteLater();
66 descr.globalInstance = 0;
67 } else {
68 QList<QUuid> allUuids = descr.individualInstances.keys();
69 while (!allUuids.isEmpty()) {
70 descr.individualInstances.take(akey: allUuids.takeFirst())->deleteLater();
71 }
72 }
73 }
74
75}
76
77/*!
78 \internal
79
80 Adds an entry to the map of service identifiers
81*/
82bool InstanceManager::addType(const QRemoteServiceRegister::Entry& e)
83{
84 QMutexLocker ml(&lock);
85
86 if (metaMap.contains(akey: e)) {
87 qWarning() << "Service" << e.serviceName() << "(" << e.interfaceName()
88 << ", " << e.version() << ")" << "already registered";
89 } else {
90 ServiceIdentDescriptor d;
91 d.entryData = e.d;
92 metaMap.insert(akey: e, avalue: d);
93 return true;
94 }
95 return false;
96}
97
98/*!
99 \internal
100
101 Returns the metaobject of a registered service object identified by its \a entry
102*/
103const QMetaObject* InstanceManager::metaObject(const QRemoteServiceRegister::Entry& entry) const
104{
105 QMutexLocker ml(&lock);
106 if (metaMap.contains(akey: entry)) {
107 return metaMap[entry].entryData->meta;
108 } else {
109 return 0;
110 }
111}
112
113/*!
114 \internal
115
116 Returns a list of all the registered entries
117*/
118QList<QRemoteServiceRegister::Entry> InstanceManager::allEntries() const
119{
120 QMutexLocker ml(&lock);
121 return metaMap.keys();
122}
123
124/*!
125 \internal
126
127 Instance manager takes ownership of service instance. Returns a null pointer
128 if \a entry cannot be mapped to a known meta object. The \a instanceId will
129 contain the unique ID for the new service instance.
130*/
131QObject* InstanceManager::createObjectInstance(const QRemoteServiceRegister::Entry& entry, QUuid& instanceId, QServiceClientCredentials& creds)
132{
133 instanceId = QUuid();
134 QMutexLocker ml(&lock);
135 if (!metaMap.contains(akey: entry))
136 return 0;
137
138 QObject* service = 0;
139 ServiceIdentDescriptor& descr = metaMap[entry];
140
141 if (descr.entryData->instanceType == QRemoteServiceRegister::GlobalInstance) {
142 if (descr.globalInstance) {
143 service = descr.globalInstance;
144 instanceId = descr.globalId;
145 descr.globalRefCount++;
146 if (!QMetaObject::invokeMethod(obj: service, member: "verifyNewServiceClientCredentials", Q_ARG(QServiceClientCredentials*, &creds))){
147 qWarning() << "Unable to authenticate new client connection on shared object" << descr.entryData->meta->className();
148 }
149 } else {
150 bool hasSecureConstructor = false;
151 const QMetaObject* metaObject = descr.entryData->meta;
152 for (int i = 0; i < metaObject->constructorCount(); ++i) {
153 const QMetaMethod method = metaObject->constructor(index: i);
154 const QList<QByteArray> params = method.parameterTypes();
155 if (params.at(i: 0) == "QServiceClientCredentials*") {
156 hasSecureConstructor = true;
157 service = metaObject->newInstance(Q_ARG(QServiceClientCredentials*, &creds));
158 break;
159 }
160 }
161 if (!hasSecureConstructor) {
162 qWarning() << "caution SFW using constructor without security credentials" << descr.entryData->meta->className();
163 service = (*descr.entryData->cptr)();
164 }
165 if (!service)
166 return 0;
167
168 descr.globalInstance = service;
169 descr.globalId = instanceId = QUuid::createUuid();
170 descr.globalRefCount = 1;
171 }
172 } else {
173 bool hasSecureConstructor = false;
174 const QMetaObject* metaObject = descr.entryData->meta;
175 for (int i = 0; i < metaObject->constructorCount(); ++i) {
176 const QMetaMethod method = metaObject->constructor(index: i);
177 const QList<QByteArray> params = method.parameterTypes();
178 if (params.at(i: 0) == "QServiceClientCredentials*") {
179 hasSecureConstructor = true;
180 service = metaObject->newInstance(Q_ARG(QServiceClientCredentials*, &creds));
181 break;
182 }
183 }
184 if (!hasSecureConstructor) {
185 qWarning() << "caution SFW using constructor without security credentials" << descr.entryData->meta->className();
186 service = (*descr.entryData->cptr)();
187 }
188 if (!service)
189 return 0;
190 instanceId = QUuid::createUuid();
191 descr.individualInstances.insert(akey: instanceId, avalue: service);
192 }
193
194 return service;
195}
196
197/*!
198 \internal
199
200 The associated service object instance will be deleted in the service process.
201 Removes an instance with \a instanceId from a map of remote service descriptors
202 using the \a entry as the key.
203
204 Emits instanceClosed() and allInstancesClosed() if no more instances are open
205*/
206void InstanceManager::removeObjectInstance(const QRemoteServiceRegister::Entry& entry, const QUuid& instanceId)
207{
208 QMutexLocker ml(&lock);
209 if (!metaMap.contains(akey: entry))
210 return;
211
212 ServiceIdentDescriptor& descr = metaMap[entry];
213 if (descr.entryData->instanceType == QRemoteServiceRegister::GlobalInstance) {
214 if (descr.globalRefCount < 1)
215 return;
216
217 if (descr.globalRefCount == 1) {
218 if (descr.globalInstance)
219 QTimer::singleShot(msec: 0, receiver: descr.globalInstance, SLOT(deleteLater()));
220 descr.globalInstance = 0;
221 descr.globalId = QUuid();
222 descr.globalRefCount = 0;
223 emit instanceClosed(entry);
224 emit instanceClosed(entry, instanceId); //internal use
225 } else {
226 descr.globalRefCount--;
227 }
228 } else {
229 QObject* service = descr.individualInstances.take(akey: instanceId);
230 if (service) {
231 service->deleteLater();
232 emit instanceClosed(entry);
233 emit instanceClosed(entry, instanceId); //internal use
234 }
235 }
236
237 // Check that no instances are open
238 if (totalInstances() < 1)
239 emit allInstancesClosed();
240}
241
242/*!
243 \internal
244
245 Provides a count of how many global and private instances are currently open
246*/
247int InstanceManager::totalInstances() const
248{
249 int total = 0;
250
251 QList<QRemoteServiceRegister::Entry> allEntries = metaMap.keys();
252 foreach (const QRemoteServiceRegister::Entry& entry, allEntries) {
253 ServiceIdentDescriptor descr = metaMap[entry];
254 total += descr.globalRefCount;
255 total += descr.individualInstances.size();
256 }
257
258 return total;
259}
260
261#include "moc_instancemanager_p.cpp"
262
263QT_END_NAMESPACE
264

source code of qtsystems/src/serviceframework/ipc/instancemanager.cpp