Keyple Service C++ Library - 3.3.5
Component of the Keyple C++ middleware
SmartCardServiceAdapter.cpp
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (c) 2025 Calypso Networks Association https://calypsonet.org/ *
3 * *
4 * See the NOTICE file(s) distributed with this work for additional *
5 * information regarding copyright ownership. *
6 * *
7 * This program and the accompanying materials are made available under the *
8 * terms of the Eclipse Public License 2.0 which is available at *
9 * http://www.eclipse.org/legal/epl-2.0 *
10 * *
11 * SPDX-License-Identifier: EPL-2.0 *
12 ******************************************************************************/
13
14#include "keyple/core/service/SmartCardServiceAdapter.hpp"
15
16#include <memory>
17#include <string>
18#include <utility>
19#include <vector>
20
21#include "keyple/core/common/CommonApiProperties.hpp"
22#include "keyple/core/plugin/PluginApiProperties.hpp"
23#include "keyple/core/plugin/PluginIOException.hpp"
24#include "keyple/core/plugin/spi/AutonomousObservablePluginSpi.hpp"
25#include "keyple/core/plugin/spi/ObservablePluginSpi.hpp"
26#include "keyple/core/plugin/spi/PluginSpi.hpp"
27#include "keyple/core/plugin/spi/PoolPluginSpi.hpp"
28#include "keyple/core/service/AutonomousObservableLocalPluginAdapter.hpp"
29#include "keyple/core/service/KeyplePluginException.hpp"
30#include "keyple/core/service/LocalPoolPluginAdapter.hpp"
31#include "keyple/core/service/ObservableLocalPluginAdapter.hpp"
32#include "keyple/core/service/ReaderApiFactoryAdapter.hpp"
33#include "keyple/core/util/KeypleAssert.hpp"
34#include "keyple/core/util/cpp/KeypleStd.hpp"
35#include "keyple/core/util/cpp/StringUtils.hpp"
36#include "keyple/core/util/cpp/exception/IllegalArgumentException.hpp"
37#include "keyple/core/util/cpp/exception/IllegalStateException.hpp"
38#include "keyple/core/util/cpp/exception/PatternSyntaxException.hpp"
39#include "keypop/card/CardApiProperties.hpp"
40#include "keypop/reader/ReaderApiProperties.hpp"
41
42namespace keyple {
43namespace core {
44namespace service {
45
46using keyple::core::common::CommonApiProperties_VERSION;
47using keyple::core::plugin::PluginApiProperties_VERSION;
48using keyple::core::plugin::PluginIOException;
49using keyple::core::plugin::spi::AutonomousObservablePluginSpi;
50using keyple::core::plugin::spi::ObservablePluginSpi;
51using keyple::core::plugin::spi::PluginSpi;
52using keyple::core::plugin::spi::PoolPluginSpi;
53using keyple::core::service::AutonomousObservableLocalPluginAdapter;
54using keyple::core::service::KeyplePluginException;
55using keyple::core::service::LocalPoolPluginAdapter;
56using keyple::core::service::ReaderApiFactoryAdapter;
57using keyple::core::util::Assert;
58using keyple::core::util::cpp::StringUtils;
59using keyple::core::util::cpp::exception::IllegalArgumentException;
60using keyple::core::util::cpp::exception::IllegalStateException;
61using keyple::core::util::cpp::exception::PatternSyntaxException;
62using keypop::card::CardApiProperties_VERSION;
63using keypop::reader::ReaderApiProperties_VERSION;
64
65const std::string SmartCardServiceAdapter::MSG_VERSION_MISMATCH_DETECTED
66 = "Version mismatch detected: % [%] uses '%' version '%' (expected '%'). "
67 "Compatibility issues "
68 "may arise\n";
69
70std::shared_ptr<SmartCardServiceAdapter> SmartCardServiceAdapter::mInstance;
71
72std::shared_ptr<SmartCardServiceAdapter>
73SmartCardServiceAdapter::getInstance()
74{
75 if (mInstance == nullptr) {
76 mInstance = std::shared_ptr<SmartCardServiceAdapter>(
77 new SmartCardServiceAdapter());
78 }
79
80 return mInstance;
81}
82
83int
84SmartCardServiceAdapter::compareVersions(
85 const std::string& providedVersion, const std::string& localVersion) const
86{
87 const std::regex re("[.]");
88
89 std::vector<std::string> providedVersions;
90 std::split(providedVersion, re, std::back_inserter(providedVersions));
91
92 std::vector<std::string> localVersions;
93 std::split(localVersion, re, std::back_inserter(localVersions));
94
95 if (providedVersions.size() != localVersions.size()) {
96 throw IllegalStateException(
97 "Inconsistent version numbers: provided = " + providedVersion
98 + ", local = " + localVersion);
99 }
100
101 int provided = 0;
102 int local = 0;
103
104 try {
105 for (const auto& v : providedVersions) {
106 provided += std::stoi(v);
107 provided *= 1000;
108 }
109 for (const auto& v : localVersions) {
110 local += std::stoi(v);
111 local *= 1000;
112 }
113
114 /* Replaced NumberFormatException by std::invalid_argument */
115 } catch (const std::invalid_argument&) {
116 throw IllegalStateException(
117 std::string("Bad version numbers: provided = ") + providedVersion
118 + ", local = " + localVersion);
119 }
120
121 /* Java uses compareTo() which returns 0 when equal */
122 return provided != local;
123}
124
125void
126SmartCardServiceAdapter::checkPluginVersion(
127 const std::shared_ptr<PluginFactorySpi> pluginFactorySpi)
128{
129 if (compareVersions(
130 pluginFactorySpi->getCommonApiVersion(),
131 CommonApiProperties_VERSION)
132 != 0) {
133 mLogger->warn(
134 MSG_VERSION_MISMATCH_DETECTED,
135 std::string("plugin"),
136 pluginFactorySpi->getPluginName(),
137 std::string("Common API"),
138 pluginFactorySpi->getCommonApiVersion(),
139 CommonApiProperties_VERSION);
140 }
141
142 if (compareVersions(
143 pluginFactorySpi->getPluginApiVersion(),
144 PluginApiProperties_VERSION)
145 != 0) {
146 mLogger->warn(
147 MSG_VERSION_MISMATCH_DETECTED,
148 std::string("plugin"),
149 pluginFactorySpi->getPluginName(),
150 std::string("Plugin API"),
151 pluginFactorySpi->getPluginApiVersion(),
152 PluginApiProperties_VERSION);
153 }
154}
155
156std::shared_ptr<Plugin>
157SmartCardServiceAdapter::registerPlugin(
158 const std::shared_ptr<KeyplePluginExtensionFactory> pluginFactory)
159{
160 Assert::getInstance().notNull(pluginFactory, "pluginFactory");
161
162 std::shared_ptr<AbstractPluginAdapter> plugin = nullptr;
163
164 const std::lock_guard<std::mutex> lock(mMutex);
165
166 try {
167 const auto factorySpi
168 = std::dynamic_pointer_cast<PluginFactorySpi>(pluginFactory);
169 const auto poolSpi
170 = std::dynamic_pointer_cast<PoolPluginFactorySpi>(pluginFactory);
171 if (factorySpi) {
172 plugin = createLocalPlugin(factorySpi);
173 } else if (poolSpi) {
174 plugin = createLocalPoolPlugin(poolSpi);
175 // } else if (pluginFactory instanceof RemotePluginFactorySpi) {
176 // plugin = createRemotePlugin((RemotePluginFactorySpi)
177 // pluginFactory);
178 } else {
179 throw IllegalArgumentException(
180 "The factory doesn't implement the right SPI");
181 }
182
183 mPlugins.insert({plugin->getName(), plugin});
184 plugin->doRegister();
185
186 } catch (const IllegalArgumentException& e) {
187 throw IllegalArgumentException(
188 "The provided plugin factory doesn't implement the plugin"
189 " API properly",
190 e);
191
192 } catch (const PluginIOException& e) {
193 throw KeyplePluginException(
194 std::string("Unable to register the plugin [") + plugin->getName()
195 + "]: " + e.getMessage(),
196 e);
197 }
198
199 return plugin;
200}
201
202void
203SmartCardServiceAdapter::unregisterPlugin(const std::string& pluginName)
204{
205 mLogger->info("Unregister plugin [%]\n", pluginName);
206
207 const std::lock_guard<std::mutex> lock(mMutex);
208
209 auto i = mPlugins.find(pluginName);
210 if (i != mPlugins.end()) {
211 std::shared_ptr<Plugin> removedPlugin = std::move(i->second);
212 std::dynamic_pointer_cast<AbstractPluginAdapter>(removedPlugin)
213 ->doUnregister();
214 mPlugins.erase(i);
215
216 } else {
217 mLogger->warn("Plugin [%] not registered\n", pluginName);
218 }
219}
220
221const std::vector<std::string>
222SmartCardServiceAdapter::getPluginNames() const
223{
224 std::vector<std::string> pluginNames;
225 for (const auto& pair : mPlugins) {
226 pluginNames.push_back(pair.first);
227 }
228
229 return pluginNames;
230}
231
232const std::vector<std::shared_ptr<Plugin>>
233SmartCardServiceAdapter::getPlugins() const
234{
235 std::vector<std::shared_ptr<Plugin>> plugins;
236 for (const auto& pair : mPlugins) {
237 plugins.push_back(pair.second);
238 }
239
240 return plugins;
241}
242
243std::shared_ptr<Plugin>
244SmartCardServiceAdapter::getPlugin(const std::string& pluginName) const
245{
246 auto it = mPlugins.find(pluginName);
247 if (it != mPlugins.end()) {
248 return it->second;
249 }
250
251 return nullptr;
252}
253
254std::shared_ptr<Plugin>
255SmartCardServiceAdapter::getPlugin(
256 const std::shared_ptr<CardReader> cardReader) const
257{
258 for (const auto& plugin : mPlugins) {
259 const auto& readers = plugin.second->getReaders();
260 if (std::any_of(
261 readers.begin(),
262 readers.end(),
263 [cardReader](const std::shared_ptr<CardReader>& reader) {
264 return reader == cardReader;
265 })) {
266 return plugin.second;
267 }
268 }
269
270 return nullptr;
271}
272
273std::shared_ptr<CardReader>
274SmartCardServiceAdapter::getReader(const std::string& readerName) const
275{
276 for (const auto& plugin : mPlugins) {
277 const auto& readers = plugin.second->getReaders();
278 auto it = std::find_if(
279 readers.begin(),
280 readers.end(),
281 [readerName](const std::shared_ptr<CardReader>& reader) {
282 return reader->getName() == readerName;
283 });
284 if (it != readers.end()) {
285 return *it;
286 }
287 }
288
289 return nullptr;
290}
291
292std::shared_ptr<CardReader>
293SmartCardServiceAdapter::findReader(const std::string& readerNameRegex) const
294{
295 for (const auto& plugin : mPlugins) {
296 std::shared_ptr<CardReader> reader(
297 plugin.second->findReader(readerNameRegex));
298 if (reader != nullptr) {
299 return reader;
300 }
301 }
302
303 return nullptr;
304}
305
306void
307SmartCardServiceAdapter::checkCardExtension(
308 const std::shared_ptr<KeypleCardExtension> cardExtension) const
309{
310 checkCardExtensionVersion(cardExtension);
311}
312
313std::unique_ptr<ReaderApiFactory>
314SmartCardServiceAdapter::getReaderApiFactory()
315{
316 return std::unique_ptr<ReaderApiFactoryAdapter>(
317 new ReaderApiFactoryAdapter());
318}
319
320void
321SmartCardServiceAdapter::checkPoolPluginVersion(
322 const std::shared_ptr<PoolPluginFactorySpi> poolPluginFactorySpi)
323{
324 if (compareVersions(
325 poolPluginFactorySpi->getCommonApiVersion(),
326 CommonApiProperties_VERSION)
327 != 0) {
328 mLogger->warn(
329 MSG_VERSION_MISMATCH_DETECTED,
330 std::string("pool plugin"),
331 poolPluginFactorySpi->getPoolPluginName(),
332 std::string("Common API"),
333 poolPluginFactorySpi->getCommonApiVersion(),
334 CommonApiProperties_VERSION);
335 }
336
337 if (compareVersions(
338 poolPluginFactorySpi->getPluginApiVersion(),
339 PluginApiProperties_VERSION)
340 != 0) {
341 mLogger->warn(
342 MSG_VERSION_MISMATCH_DETECTED,
343 std::string("pool plugin"),
344 poolPluginFactorySpi->getPoolPluginName(),
345 std::string("Plugin API"),
346 poolPluginFactorySpi->getPluginApiVersion(),
347 PluginApiProperties_VERSION);
348 }
349}
350
351void
352SmartCardServiceAdapter::checkCardExtensionVersion(
353 const std::shared_ptr<KeypleCardExtension> cardExtension) const
354{
355 if (compareVersions(
356 cardExtension->getCommonApiVersion(), CommonApiProperties_VERSION)
357 != 0) {
358 const auto& c = *cardExtension.get();
359 mLogger->warn(
360 MSG_VERSION_MISMATCH_DETECTED,
361 std::string("card extension"),
362 std::string(typeid(c).name()),
363 std::string("Common API"),
364 cardExtension->getCommonApiVersion(),
365 CommonApiProperties_VERSION);
366 }
367
368 if (compareVersions(
369 cardExtension->getCardApiVersion(), CardApiProperties_VERSION)
370 != 0) {
371 const auto& c = *cardExtension.get();
372 mLogger->warn(
373 MSG_VERSION_MISMATCH_DETECTED,
374 std::string("card extension"),
375 std::string(typeid(c).name()),
376 std::string("Card API"),
377 cardExtension->getCardApiVersion(),
378 CardApiProperties_VERSION);
379 }
380
381 if (compareVersions(
382 cardExtension->getReaderApiVersion(), ReaderApiProperties_VERSION)
383 != 0) {
384 const auto& c = *cardExtension.get();
385 mLogger->warn(
386 MSG_VERSION_MISMATCH_DETECTED,
387 std::string("card extension"),
388 std::string(typeid(c).name()),
389 std::string("Reader API"),
390 cardExtension->getReaderApiVersion(),
391 ReaderApiProperties_VERSION);
392 }
393}
394
395void
396SmartCardServiceAdapter::checkPluginRegistration(const std::string& pluginName)
397{
398 mLogger->info("Registering a new Plugin to the service : %\n", pluginName);
399
400 const auto it = mPlugins.find(pluginName);
401 if (it != mPlugins.end()) {
402 throw IllegalStateException(
403 "Plugin [" + pluginName
404 + "] has already been registered to the service.");
405 }
406}
407
408std::shared_ptr<AbstractPluginAdapter>
409SmartCardServiceAdapter::createLocalPlugin(
410 std::shared_ptr<PluginFactorySpi> pluginFactorySpi)
411{
412 checkPluginRegistration(pluginFactorySpi->getPluginName());
413 checkPluginVersion(pluginFactorySpi);
414
415 std::shared_ptr<PluginSpi> pluginSpi = pluginFactorySpi->getPlugin();
416
417 if (pluginSpi->getName() != pluginFactorySpi->getPluginName()) {
418 throw IllegalArgumentException(
419 std::string("Plugin name [") + pluginSpi->getName()
420 + std::string("] mismatches the expected name [")
421 + pluginFactorySpi->getPluginName()
422 + std::string("] provided by the factory"));
423 }
424
425 std::shared_ptr<AbstractPluginAdapter> plugin = nullptr;
426
427 auto observable = std::dynamic_pointer_cast<ObservablePluginSpi>(pluginSpi);
428 if (observable) {
429 plugin = std::make_shared<ObservableLocalPluginAdapter>(observable);
430 } else {
431 auto autonomous
432 = std::dynamic_pointer_cast<AutonomousObservablePluginSpi>(
433 pluginSpi);
434 if (autonomous) {
435 plugin = std::make_shared<AutonomousObservableLocalPluginAdapter>(
436 autonomous);
437 } else {
438 plugin = std::make_shared<LocalPluginAdapter>(pluginSpi);
439 }
440 }
441
442 return plugin;
443}
444
445std::shared_ptr<AbstractPluginAdapter>
446SmartCardServiceAdapter::createLocalPoolPlugin(
447 std::shared_ptr<PoolPluginFactorySpi> poolPluginFactorySpi)
448{
449 checkPluginRegistration(poolPluginFactorySpi->getPoolPluginName());
450 checkPoolPluginVersion(poolPluginFactorySpi);
451
452 std::shared_ptr<PoolPluginSpi> poolPluginSpi
453 = poolPluginFactorySpi->getPoolPlugin();
454
455 if (poolPluginSpi->getName() != poolPluginFactorySpi->getPoolPluginName()) {
456 throw IllegalArgumentException(
457 std::string("Pool plugin name [") + poolPluginSpi->getName()
458 + "] mismatches the expected name ["
459 + poolPluginFactorySpi->getPoolPluginName()
460 + "] provided by the factory");
461 }
462
463 return std::make_shared<LocalPoolPluginAdapter>(poolPluginSpi);
464}
465
466} /* namespace service */
467} /* namespace core */
468} /* namespace keyple */