Hello team,
We have a specific use case, in which, when a type of card is detected we stop everything and let another application handle the card.
This revealed an issue in Keyple as we still keep interacting with the reader after a stopCardDetection() has been called.
finalizeCardProcessing() is called, switching the statemachine to WAIT_FOR_CARD_REMOVAL and starting an active card presence monitoring.
03-07-24 18:28:34.317 1 DEBUG SmartcardNfcReader Finishing handling the card
03-07-24 18:28:34.317 1 DEBUG org.eclipse.keyple.core.service.ObservableLocalReaderAdapter Reader 'BluebirdReader' of plugin 'BluebirdPlugin' starts the removal sequence of the card.
03-07-24 18:28:34.317 1 VERBOSE org.eclipse.keyple.core.service.WaitForCardProcessingStateAdapter [BluebirdReader] onInternalEvent => Event CARD_PROCESSED received in currentState WAIT_FOR_CARD_PROCESSING
03-07-24 18:28:34.318 1 VERBOSE org.eclipse.keyple.core.service.ObservableReaderStateServiceAdapter [BluebirdReader] Switch currentState from WAIT_FOR_CARD_PROCESSING to WAIT_FOR_CARD_REMOVAL
03-07-24 18:28:34.318 1 VERBOSE org.eclipse.keyple.core.service.AbstractObservableStateAdapter [BluebirdReader] onDeactivate => WAIT_FOR_CARD_PROCESSING
03-07-24 18:28:34.319 1 VERBOSE org.eclipse.keyple.core.service.AbstractObservableStateAdapter [BluebirdReader] onActivate => WAIT_FOR_CARD_REMOVAL
stopCardDetection() is called to stop all operations on the card and reader and let the other application work
03-07-24 18:28:34.320 1 DEBUG SmartcardNfcReader stopCardDetection()
03-07-24 18:28:34.321 1280 DEBUG org.eclipse.keyple.core.service.CardRemovalActiveMonitoringJobAdapter [BluebirdReader] Polling from isCardPresentPing
03-07-24 18:28:34.321 1 DEBUG org.eclipse.keyple.core.service.ObservableLocalReaderAdapter Reader 'BluebirdReader' of plugin 'BluebirdPlugin' stops the card detection.
03-07-24 18:28:34.322 1280 VERBOSE org.eclipse.keyple.core.service.ObservableLocalReaderAdapter [BluebirdReader] Ping card
03-07-24 18:28:34.322 1 DEBUG BluebirdReaderAdapter onStopDetection()
03-07-24 18:28:34.322 1280 DEBUG BluebirdReaderAdapter transmitApdu() apduIn=00C0000000
03-07-24 18:28:34.324 1 DEBUG BluebirdReaderAdapter extNfcReader.stopScan = 0
03-07-24 18:28:34.326 1 VERBOSE org.eclipse.keyple.core.service.WaitForCardRemovalStateAdapter [BluebirdReader] onInternalEvent => Event STOP_DETECT received in currentState WAIT_FOR_CARD_REMOVAL
03-07-24 18:28:34.327 1 VERBOSE org.eclipse.keyple.core.service.LocalReaderAdapter [BluebirdReader] closeLogicalChannel => Closing of the logical channel.
03-07-24 18:28:34.327 1 DEBUG BluebirdReaderAdapter closePhysicalChannel()
03-07-24 18:28:34.327 1 DEBUG org.eclipse.keyple.core.service.ObservableLocalReaderAdapter Reader 'BluebirdReader' notifies the reader event 'CARD_REMOVED' to 1 observer(s).
We see at the same time the state machine being "stopped" (WAIT_FOR_START_DETECTION) and the removal monitoring job requested to stop. (It's a simple request and not an interruption. Ongoing jobs are allowed to finish)
03-07-24 18:28:34.379 1280 DEBUG BluebirdReaderAdapter transmitApdu() result=6D00
03-07-24 18:28:34.381 1280 VERBOSE org.eclipse.keyple.core.service.CardRemovalActiveMonitoringJobAdapter [BluebirdReader] Polling retries : 1
03-07-24 18:28:34.556 1 DEBUG PeripheralObserver onChange(true,null
03-07-24 18:28:34.557 1 VERBOSE org.eclipse.keyple.core.service.ObservableReaderStateServiceAdapter [BluebirdReader] Switch currentState from WAIT_FOR_CARD_REMOVAL to WAIT_FOR_START_DETECTION
03-07-24 18:28:34.557 1 VERBOSE org.eclipse.keyple.core.service.AbstractObservableStateAdapter [BluebirdReader] onDeactivate => WAIT_FOR_CARD_REMOVAL
03-07-24 18:28:34.557 1 DEBUG org.eclipse.keyple.core.service.CardRemovalActiveMonitoringJobAdapter [BluebirdReader] Stop Polling
03-07-24 18:28:34.558 1 VERBOSE org.eclipse.keyple.core.service.AbstractObservableStateAdapter [BluebirdReader] onDeactivate => cancel monitoring job CardRemovalActiveMonitoringJobAdapter by thread interruption true
03-07-24 18:28:34.558 1 VERBOSE org.eclipse.keyple.core.service.AbstractObservableStateAdapter [BluebirdReader] onActivate => WAIT_FOR_START_DETECTION
03-07-24 18:28:34.558 1 DEBUG SmartcardNfcReader remove observer
03-07-24 18:28:34.558 1 DEBUG org.eclipse.keyple.core.service.ObservationManagerAdapter Reader 'BluebirdReader' of plugin 'BluebirdPlugin' is removing the observer 'BluebirdNfcReader'.
200ms later the card removal monitoring job awakens from a Thread.sleep, understands that a stop has been requested BUT tries to close the physical channel and send a CARD_REMOVED event.
03-07-24 18:28:34.582 1280 DEBUG org.eclipse.keyple.core.service.CardRemovalActiveMonitoringJobAdapter [BluebirdReader] Polling loop has been stopped
03-07-24 18:28:34.583 1280 VERBOSE org.eclipse.keyple.core.service.WaitForCardRemovalStateAdapter [BluebirdReader] onInternalEvent => Event CARD_REMOVED received in currentState WAIT_FOR_CARD_REMOVAL
03-07-24 18:28:34.583 1280 VERBOSE org.eclipse.keyple.core.service.LocalReaderAdapter [BluebirdReader] closeLogicalChannel => Closing of the logical channel.
03-07-24 18:28:34.583 1280 DEBUG BluebirdReaderAdapter closePhysicalChannel()
03-07-24 18:28:34.585 1280 DEBUG org.eclipse.keyple.core.service.ObservableLocalReaderAdapter Reader 'BluebirdReader' notifies the reader event 'CARD_REMOVED' to 0 observer(s).
03-07-24 18:28:34.591 1280 VERBOSE org.eclipse.keyple.core.service.ObservableReaderStateServiceAdapter [BluebirdReader] Switch currentState from WAIT_FOR_START_DETECTION to WAIT_FOR_CARD_INSERTION
03-07-24 18:28:34.591 1280 VERBOSE org.eclipse.keyple.core.service.AbstractObservableStateAdapter [BluebirdReader] onDeactivate => WAIT_FOR_START_DETECTION
03-07-24 18:28:34.592 1280 VERBOSE org.eclipse.keyple.core.service.AbstractObservableStateAdapter [BluebirdReader] onActivate => WAIT_FOR_CARD_INSERTION
This behavior is very problematic as we have already stopped everything and the reader is currently used by another application.
I believe that the issue is in this finally block and simply checking if the loop has been stopped before should fix it.
|
} finally { |
|
monitoringState.onEvent(ObservableLocalReaderAdapter.InternalEvent.CARD_REMOVED); |
|
} |
} finally {
if(!loop.get()) {
monitoringState.onEvent(ObservableLocalReaderAdapter.InternalEvent.CARD_REMOVED);
}
}
Hello team,
We have a specific use case, in which, when a type of card is detected we stop everything and let another application handle the card.
This revealed an issue in Keyple as we still keep interacting with the reader after a
stopCardDetection()has been called.finalizeCardProcessing()is called, switching the statemachine toWAIT_FOR_CARD_REMOVALand starting an active card presence monitoring.stopCardDetection()is called to stop all operations on the card and reader and let the other application workWe see at the same time the state machine being "stopped" (
WAIT_FOR_START_DETECTION) and the removal monitoring job requested to stop. (It's a simple request and not an interruption. Ongoing jobs are allowed to finish)200ms later the card removal monitoring job awakens from a
Thread.sleep, understands that a stop has been requested BUT tries to close the physical channel and send aCARD_REMOVEDevent.This behavior is very problematic as we have already stopped everything and the reader is currently used by another application.
I believe that the issue is in this
finallyblock and simply checking if the loop has been stopped before should fix it.keyple-service-java-lib/src/main/java/org/eclipse/keyple/core/service/CardRemovalActiveMonitoringJobAdapter.java
Lines 115 to 117 in df389b7