This guide is intended to help a user of version 0.8.1 of Keyple Java to upgrade his application to the 0.9 alpha version of the library.
From a user API point of view, the changes relate to the following topics:
The registerPlugin
method of the SeProxyService
class now returns the reference of the registered plugin.
This makes it possible, for example, to perform a reader setup in an application such as this one:
// Create a PcscPlugin and register it into the SeProxyService
ReaderPlugin pcscPlugin = seProxyService.registerPlugin(new PcscPluginFactory());`
// Get the PO reader from the plugin
SeReader poReader = pcscPlugin.getReader("ASK LoGO 0");
The AidSelector
, Selector
and PoSelector
classes now follow the Fluent Builder pattern for better handling of optional parameters.
The construction of an AidSelector
is as follows:
AidSelector appAidSelector = AidSelector.builder()
.aidToSelect(AID)
.fileControlInformation(AidSelector.FileControlInformation.FCI)
.fileOccurrence(AidSelector.FileOccurrence.FIRST)
.build();
The fileControlInformation
and fileOccurrence
fields are optional (shown here with their default values), so a simple version can be :
AidSelector aidSelector = AidSelector.builder().aidToSelect(CalypsoClassicInfo.AID).build();
The construction of a SeSelector
is as follows:
seSelector = SeSelector.builder()
.seProtocol(SeCommonProtocols.PROTOCOL_ISO14443_4)
.aidSelector(appAidSelector)
.build();
The PoSelector
adds the possibility to specify that an invalidated PO should be processed
seSelector = SeSelector.builder()
.seProtocol(SeCommonProtocols.PROTOCOL_ISO14443_4)
.aidSelector(appAidSelector)
.invalidatedPo(InvalidatedPo.ACCEPT)
.build();
The management of PO commands to be performed after the selection step (when it has been successful) is handled by the methods of the PoSelectionRequest
class:
public void prepareReadRecordFile(byte sfi, int recordNumber)
public void prepareSelectFile(byte[] lid)
public void prepareSelectFile(short lid)
Note that from now the “prepare” methods no longer return indexes, the data will be placed in the CalypsoPo object.
The MatchingSelection
class no longer exists.
In the class SelectionsResult
(see processDefaultSelection/processExplicitSelection
):
getActiveSelection
is replaced by getActiveMatchingSe
which returns an AbstractMatchingSe
object (the still existing hasActiveSelection
method must be used before)
getMatchingSelection
is replaced by getMatchingSe
which returns an AbstractMatchingSe
object (may be null if the index provided does not correspond to a successful selection case)
getMatchingSelections
now returns a Map containing a list of associated AbstractMatchingSe
with the selection index that produced it (Map<Integer, AbstractMatchingSe>
)
a new hasSelectionMatched
method indicates whether the selection index provided corresponds to a successful selection case
a new getActiveSelectionIndex
method returns the index of the active selection (the still existing hasActiveSelection
method must be used before)
These parameters are defined via the PoSecuritySettings
class, whose construction now follows the Fluent Builder pattern.
All parameters are optional except the SamResource
.
Here is an example of a complete PoSecuritySettings
build:
poSecuritySettings = new PoSecuritySettings.PoSecuritySettingsBuilder(samResource)
.sessionDefaultKif(AccessLevel.SESSION_LVL_PERSO, DEFAULT_KIF_PERSO)
.sessionDefaultKif(AccessLevel.SESSION_LVL_LOAD, DEFAULT_KIF_LOAD)
.sessionDefaultKif(AccessLevel.SESSION_LVL_DEBIT, DEFAULT_KIF_DEBIT)
.sessionDefaultKeyRecordNumber(AccessLevel.SESSION_LVL_PERSO, DEFAULT_KEY_RECORD_NUMBER_PERSO)
.sessionDefaultKeyRecordNumber(AccessLevel.SESSION_LVL_LOAD, DEFAULT_KEY_RECORD_NUMBER_LOAD)
.sessionDefaultKeyRecordNumber(AccessLevel.SESSION_LVL_DEBIT, DEFAULT_KEY_RECORD_NUMBER_DEBIT)
.sessionModificationMode(ModificationMode.ATOMIC)
.ratificationMode(RatificationMode.CLOSE_RATIFIED)
.sessionAuthorizedKvcList(authKvcs)
.build();
Since PoSecuritySettings now integrates SamResource, the construction of PoTransaction has evolved slightly.
Here is an example:
PoTransaction poTransaction = new PoTransaction(new PoResource(poReader, calypsoPo), poSecuritySettings);
Just as with the “prepare” commands used for selection, the “prepare” commands used for transactions no longer return indexes.
The available commands in version 0.9 are:
public final void prepareSelectFile(SelectFileControl control)
public final void prepareSelectFile(short lid)
public final void prepareSelectFile(byte[] lid)
public final void prepareReadRecordFile(byte sfi, int recordNumber)
public final void prepareReadRecordFile(byte sfi, int firstRecordNumber, int numberOfRecords, int recordSize))
public final void prepareReadCounterFile(byte sfi, int countersNumber)
public final void prepareUpdateRecord(byte sfi, int recordNumber, byte[] recordData)
public final void prepareWriteRecord(byte sfi, int recordNumber, byte[] recordData)
public final void prepareAppendRecord(byte sfi, byte[] recordData)
public final void prepareIncreaseCounter(byte sfi, int counterNumber, int incValue)
public final void prepareDecreaseCounter(byte sfi, int counterNumber, int decValue)
The “process” commands have also been revised and simplified.
They all return void
.
In case of failure a exception is raised (see below).
public final void processOpening(PoTransaction.SessionSetting.AccessLevel accessLevel)
The ModificationMode
is no longer required since it is integrated in the PoSecuritySettings
.
Parameters previously used to specify that a file is read at login are removed.
Instead, the first prepareReadFile command will be automatically taken into account.
public final void processPoCommands()
public final void processPoCommandsInSession()
public final void processCancel(ChannelControl channelControl)
public final void processClosing(ChannelControl channelControl)
This is a major evolution of the Keyple API. Previously, data read from Calyspo POs were retrieved by applications using “parser” methods.
With Keyple API 0.9, Calypso PO data is made available in the CalypsoPo object obtained during selection and enriched all along the operations performed with PoTransaction.
The public getter methods of CalypsoPo are:
public final String getDfName()
public final byte[] getDfNameBytes()
public final String getApplicationSerialNumber()
public final byte[] getApplicationSerialNumberBytes()
public final String getAtr()
public final String getStartupInfo()
public final PoRevision getRevision()
public final byte getSessionModification()
public final byte getApplicationType()
public final byte getApplicationSubtype()
public final byte getPlatform()
public final byte getSoftwareIssuer()
public final byte getSoftwareVersion()
public final byte getSoftwareRevision()
public final boolean isDeselectRatificationSupported()
public final boolean isConfidentialSessionModeSupported()
public final boolean isPublicAuthenticationSupported()
public final boolean isPinFeatureAvailable()
public final boolean isSvFeatureAvailable()
public final boolean isDfInvalidated()
public final boolean isDfRatified()
public final DirectoryHeader getDirectoryHeader()
public final ElementaryFile getFileBySfi(byte sfi)
public final ElementaryFile getFileByLid(short lid)
public final Map<Byte, ElementaryFile> getAllFiles()
Four new classes DirectoryHeader
, ElementaryFile
, FileHeader
and FileData
have been added.
The public getters for this class are:
public short getLid()
public byte[] getAccessConditions()
public byte[] getKeyIndexes()
public byte getDfStatus()
public byte getKif(AccessLevel level)
public byte getKvc(AccessLevel level)
public String toString()
The public getters for this class are:
public byte getSfi()
public FileHeader getHeader()
public FileData getData()
public String toString()
The public getters for this class are:
public short getLid()
public int getRecordsNumber()
public int getRecordSize()
public FileType getType()
public byte getDfStatus()
public boolean isShared()
public Short getSharedReference()
public byte[] getAccessConditions()
public byte[] getKeyIndexes()
public String toString()
The public getters for this class are:
public byte[] getContent()
public byte[] getContent(int numRecord)
public byte[] getContent(int numRecord, int dataOffset, int dataLength)
public SortedMap<Integer, byte[]> getAllRecordsContent()
public int getContentAsCounterValue(int numCounter)
public SortedMap<Integer, Integer> getAllCountersValue()
public String toString()
So, for example to extract the contents of contract files present in the PO, the code might look like this:
[...]
/* Read all 4 contracts command, record size set to 29 */
poTransaction.prepareReadRecordFile(CalypsoClassicInfo.SFI_Contracts,
CalypsoClassicInfo.RECORD_NUMBER_1, 4, 29);
/* proceed with the sending of commands, don't close the channel */
poTransaction.processPoCommandsInSession();
ElementaryFile efContracts = calypsoPo.getFileBySfi(CalypsoClassicInfo.SFI_Contracts);
SortedMap<Integer, byte[]> records = efContracts.getData().getAllRecordsContent();
for (Map.Entry<Integer, byte[]> entry : records.entrySet()) {
logger.info("Contract #{}: {}", entry.getKey(),
ByteArrayUtil.toHex(entry.getValue()));
}
[...]
Since version 0.9, all Keyple exceptions are of the RuntimeException type.
Catching exceptions is therefore now optional.
However, it is possible to selectively catch certain exceptions in order to deal with particular cases.
The new hierarchy of Keyple exceptions is shown here