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