Keyple Service C++ Library - 3.3.5
Component of the Keyple C++ middleware
CardSelectionManagerAdapter.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/CardSelectionManagerAdapter.hpp"
15
16#include <memory>
17#include <string>
18#include <vector>
19
20#include "keyple/core/service/AbstractReaderAdapter.hpp"
21#include "keyple/core/service/CardSelectionResultAdapter.hpp"
22#include "keyple/core/service/CardSelectionScenarioAdapter.hpp"
23#include "keyple/core/service/ObservableLocalReaderAdapter.hpp"
24#include "keyple/core/service/ScheduledCardSelectionsResponseAdapter.hpp"
25#include "keyple/core/util/KeypleAssert.hpp"
26#include "keyple/core/util/cpp/exception/IllegalArgumentException.hpp"
27#include "keyple/core/util/cpp/exception/IllegalStateException.hpp"
28#include "keyple/core/util/cpp/exception/UnsupportedOperationException.hpp"
29#include "keypop/card/CardBrokenCommunicationException.hpp"
30#include "keypop/card/CardSelectionResponseApi.hpp"
31#include "keypop/card/ParseException.hpp"
32#include "keypop/card/ReaderBrokenCommunicationException.hpp"
33#include "keypop/card/spi/CardSelectionExtensionSpi.hpp"
34#include "keypop/reader/CardCommunicationException.hpp"
35#include "keypop/reader/ReaderCommunicationException.hpp"
36#include "keypop/reader/cpp/CardSelectorBase.hpp"
37#include "keypop/reader/selection/InvalidCardResponseException.hpp"
38#include "keypop/reader/selection/spi/SmartCard.hpp"
39
40namespace keyple {
41namespace core {
42namespace service {
43
44using keyple::core::util::Assert;
45using keyple::core::util::cpp::exception::IllegalArgumentException;
46using keyple::core::util::cpp::exception::IllegalStateException;
47using keyple::core::util::cpp::exception::UnsupportedOperationException;
48using keypop::card::CardBrokenCommunicationException;
49using keypop::card::CardSelectionResponseApi;
50using keypop::card::ParseException;
51using keypop::card::ReaderBrokenCommunicationException;
52using keypop::card::spi::CardSelectionExtensionSpi;
53using keypop::reader::CardCommunicationException;
54using keypop::reader::ReaderCommunicationException;
55using keypop::reader::cpp::CardSelectorBase;
56using keypop::reader::selection::InvalidCardResponseException;
57using keypop::reader::selection::spi::SmartCard;
58
59const std::string CardSelectionManagerAdapter::MULTI_SELECTION_PROCESSING
60 = "multiSelectionProcessing";
61const std::string CardSelectionManagerAdapter::CHANNEL_CONTROL
62 = "channelControl";
63const std::string CardSelectionManagerAdapter::CARD_SELECTORS_TYPES
64 = "cardSelectorsTypes";
65const std::string CardSelectionManagerAdapter::CARD_SELECTORS = "cardSelectors";
66const std::string CardSelectionManagerAdapter::CARD_SELECTIONS_TYPES
67 = "cardSelectionsTypes";
68const std::string CardSelectionManagerAdapter::CARD_SELECTIONS
69 = "cardSelections";
70const std::string CardSelectionManagerAdapter::DEFAULT_CARD_SELECTIONS
71 = "defaultCardSelections";
72
73CardSelectionManagerAdapter::CardSelectionManagerAdapter()
74: mMultiSelectionProcessing(MultiSelectionProcessing::FIRST_MATCH)
75, mChannelControl(ChannelControl::KEEP_OPEN)
76{
77}
78
79void
80CardSelectionManagerAdapter::setMultipleSelectionMode()
81{
82 mMultiSelectionProcessing = MultiSelectionProcessing::PROCESS_ALL;
83}
84
85int
86CardSelectionManagerAdapter::prepareSelection(
87 const std::shared_ptr<CardSelectorBase> cardSelector,
88 const std::shared_ptr<CardSelectionExtension> cardSelectionExtension)
89{
90 Assert::getInstance()
91 .notNull(cardSelector, "cardSelector")
92 .notNull(cardSelectionExtension, "cardSelectionExtension");
93
94 auto cardSelectionExtensionSpi
95 = std::dynamic_pointer_cast<CardSelectionExtensionSpi>(
96 cardSelectionExtension);
97 if (!cardSelectionExtensionSpi) {
98 throw IllegalArgumentException(
99 "The provided 'cardSelectionExtension' must be an instance"
100 " of 'CardSelectionExtensionSpi");
101 }
102
103 /* Keep the selection request */
104 mCardSelectors.push_back(cardSelector);
105 mCardSelections.push_back(
106 std::dynamic_pointer_cast<CardSelectionExtensionSpi>(
107 cardSelectionExtension));
108 mCardSelectionRequests.push_back(
109 std::dynamic_pointer_cast<CardSelectionExtensionSpi>(
110 cardSelectionExtension)
111 ->getCardSelectionRequest());
112
113 /* Return the selection index (starting at 0) */
114 return static_cast<int>(mCardSelections.size()) - 1;
115}
116
117void
118CardSelectionManagerAdapter::prepareReleaseChannel()
119{
120 mChannelControl = ChannelControl::CLOSE_AFTER;
121}
122
123const std::shared_ptr<CardSelectionResult>
124CardSelectionManagerAdapter::processCardSelectionScenario(
125 std::shared_ptr<CardReader> reader)
126{
127 Assert::getInstance().notNull(reader, "reader");
128
129 /* Communicate with the card to make the actual selection */
130 std::vector<std::shared_ptr<CardSelectionResponseApi>>
131 cardSelectionResponses;
132
133 try {
134 cardSelectionResponses
135 = std::dynamic_pointer_cast<AbstractReaderAdapter>(reader)
136 ->transmitCardSelectionRequests(
137 mCardSelectors,
138 mCardSelectionRequests,
139 mMultiSelectionProcessing,
140 mChannelControl);
141
142 } catch (const ReaderBrokenCommunicationException& e) {
143 throw ReaderCommunicationException(e.getMessage(), e);
144
145 } catch (const CardBrokenCommunicationException& e) {
146 throw CardCommunicationException(e.getMessage(), e);
147 }
148
149 /* Analyze the received responses */
150 return processCardSelectionResponses(cardSelectionResponses);
151}
152
153void
154CardSelectionManagerAdapter::scheduleCardSelectionScenario(
155 std::shared_ptr<ObservableCardReader> observableCardReader,
156 const NotificationMode notificationMode)
157{
158 Assert::getInstance().notNull(observableCardReader, "observableCardReader");
159
160 auto cardSelectionScenario = std::make_shared<CardSelectionScenarioAdapter>(
161 mCardSelectors,
162 mCardSelectionRequests,
163 mMultiSelectionProcessing,
164 mChannelControl);
165
166 auto local = std::dynamic_pointer_cast<ObservableLocalReaderAdapter>(
167 observableCardReader);
168 // auto remote
169 // =std::dynamic_pointer_cast<ObservableRemoteReaderAdapter>(observableCardReader);
170 if (local) {
171 local->scheduleCardSelectionScenario(
172 cardSelectionScenario, notificationMode);
173 // } else if (remote) {
174 // remote->scheduleCardSelectionScenario(cardSelectionScenario,
175 // notificationMode);
176 } else {
177 throw IllegalArgumentException("Not a Keyple reader implementation");
178 }
179}
180
181const std::shared_ptr<CardSelectionResult>
182CardSelectionManagerAdapter::parseScheduledCardSelectionsResponse(
183 const std::shared_ptr<ScheduledCardSelectionsResponse>
184 scheduledCardSelectionsResponse)
185{
186 Assert::getInstance().notNull(
187 scheduledCardSelectionsResponse, "scheduledCardSelectionsResponse");
188
189 return processCardSelectionResponses(
190 std::static_pointer_cast<ScheduledCardSelectionsResponseAdapter>(
191 scheduledCardSelectionsResponse)
192 ->getCardSelectionResponses());
193}
194
195const std::string
196CardSelectionManagerAdapter::exportProcessedCardSelectionScenario() const
197{
198 /* TODO: necessary when implementing distributed mode */
199
200 throw IllegalStateException("not implemented");
201}
202
203const std::shared_ptr<CardSelectionResult>
204CardSelectionManagerAdapter::importProcessedCardSelectionScenario(
205 const std::string& /*processedCardSelectionScenario*/) const
206{
207 /* TODO: necessary when implementing distributed mode */
208
209 throw IllegalStateException("not implemented");
210}
211
212const std::shared_ptr<CardSelectionResult>
213CardSelectionManagerAdapter::processCardSelectionResponses(
214 const std::vector<std::shared_ptr<CardSelectionResponseApi>>&
215 cardSelectionResponses)
216{
217 Assert::getInstance().isInRange(
218 cardSelectionResponses.size(),
219 1,
220 mCardSelections.size(),
221 "cardSelectionResponses");
222
223 auto cardSelectionsResult = std::make_shared<CardSelectionResultAdapter>();
224 int index = 0;
225
226 for (const auto& cardSelectionResponse : cardSelectionResponses) {
227 if (cardSelectionResponse->hasMatched()) {
228 /* Invoke the parse method defined by the card extension to retrieve
229 * the smart card */
230 std::shared_ptr<SmartCard> smartCard = nullptr;
231 try {
232 smartCard = std::dynamic_pointer_cast<SmartCard>(
233 mCardSelections[index]->parse(cardSelectionResponse));
234
235 } catch (const ParseException& e) {
236 throw InvalidCardResponseException(
237 "Error occurred while parsing the card response: "
238 + e.getMessage(),
239 e);
240
241 } catch (const UnsupportedOperationException&) {
242 mLogger->warn(
243 "Unable to parse card selection responses due to "
244 "missing card "
245 "extensions in runtime environment");
246 cardSelectionsResult
247 = std::make_shared<CardSelectionResultAdapter>(); // Empty
248 // result
249 break;
250 }
251
252 cardSelectionsResult->addSmartCard(index, smartCard);
253 }
254
255 index++;
256 }
257
258 mCardSelectionResponses = cardSelectionResponses;
259
260 return cardSelectionsResult;
261}
262
263const std::string
264CardSelectionManagerAdapter::exportCardSelectionScenario() const
265{
266 /* TODO: necessary when implementing distributed mode */
267
268 return "";
269}
270
271int
272CardSelectionManagerAdapter::importCardSelectionScenario(
273 const std::string& cardSelectionScenario)
274{
275 /* TODO: necessary when implementing distributed mode */
276
277 (void)cardSelectionScenario;
278
279 return 0;
280}
281
282} /* namespace service */
283} /* namespace core */
284} /* namespace keyple */