Smart Cards diariamente tem se tornado um micro-dispositivo preferido para armazenar dados sigilosos, identificar pessoas, realizar operações de autenticação, etc.
Entretanto quando se usa Smart Cards existem riscos de ocorrerem falhas durante a execução a qualquer momento.
Falhas podem ocorrer por erros computacionais, remoção do Smart Card do Leitor, corte na alimentação de energia da CPU do cartão, etc.
No entanto o JCRE provê um robusto mecanismo que garante operações atômicas, esse mecanismo suporta 2 níveis.
Primeiro, a plataforma Java Card garante que qualquer atualização em um simples campo de um objeto persistente ou um campo simples em uma classe é atômica.
Segundo, a plataforma Java Card suporta um modelo de transação, o qual um applet pode agrupar uma série de atualizações, nesse modelo toda atualização é assegurada atômicamente.
Atomicidade (Atomicity).
Atomicity em Java Card quer dizer que qualquer atualização a um campo simples de um objeto persistente inclusive arrays, ou um campo de uma classe é totalmente garantida, caso contrário os dados anteriores serão restaurados. Por exemplo, um campo em um objeto armazena um valor 1 e começa a ser atualizado para o valor 2, nesse exato momento o cartão é removido do leitor, na próxima vez em que o cartão for alimentado o valor desse campo é restaurado para 1 novamente.
Este conceito de Atomicidade somente é aplicado sobre o armazenamento persistente, no caso de armazenamento de natureza transiente, os dados não serão restaurados em caso de perda de energia ou falhas serão iniciados com os valores padrões (zero, false ou null).
Atualizações de um Array.
A classe javacard.framework.Util provê o método arrayCopy que garante a Atomicidade durante a atualização de um bloco de dados em arrays.
Entretanto para garantir a Atomicidade arrayCopy necessita de mais ciclos de escrita em EEPROM, e isso tende a ser lento. Caso seu Applet não precise de atomicidade durante atualizações de arrays considere o uso do método Util.arrayCopyNonAtomic.
Transações (Transactions)
Transações são geralmente utilizadas quando um Applet necessitar que vários campos e objetos diferentes devem ser atualizados de maneira atômica por exemplo um Applet Moedeiro deve realizar as seguintes operações:
No entanto o JCRE provê um robusto mecanismo que garante operações atômicas, esse mecanismo suporta 2 níveis.
Primeiro, a plataforma Java Card garante que qualquer atualização em um simples campo de um objeto persistente ou um campo simples em uma classe é atômica.
Segundo, a plataforma Java Card suporta um modelo de transação, o qual um applet pode agrupar uma série de atualizações, nesse modelo toda atualização é assegurada atômicamente.
Atomicidade (Atomicity).
Atomicity em Java Card quer dizer que qualquer atualização a um campo simples de um objeto persistente inclusive arrays, ou um campo de uma classe é totalmente garantida, caso contrário os dados anteriores serão restaurados. Por exemplo, um campo em um objeto armazena um valor 1 e começa a ser atualizado para o valor 2, nesse exato momento o cartão é removido do leitor, na próxima vez em que o cartão for alimentado o valor desse campo é restaurado para 1 novamente.
Este conceito de Atomicidade somente é aplicado sobre o armazenamento persistente, no caso de armazenamento de natureza transiente, os dados não serão restaurados em caso de perda de energia ou falhas serão iniciados com os valores padrões (zero, false ou null).
Atualizações de um Array.
A classe javacard.framework.Util provê o método arrayCopy que garante a Atomicidade durante a atualização de um bloco de dados em arrays.
public static short arrayCopy( byte[] src,short srcOff,byte[] dest,short desOff,short length )O método Util.arrayCopy garante que cada byte será corretamente copiado, ou o destino é restaurado para os valores anteriores, porém caso o destino seja um objeto transiente seus dados não serão preservados.
Entretanto para garantir a Atomicidade arrayCopy necessita de mais ciclos de escrita em EEPROM, e isso tende a ser lento. Caso seu Applet não precise de atomicidade durante atualizações de arrays considere o uso do método Util.arrayCopyNonAtomic.
public static short arrayCopyNonAtomic( byte[] src,short srcOff,byte[] dest,short desOff,short length )Ao contrário do arrayCopy, o método arrayCopyNonAtomic não utiliza a atomicidade durante a cópia, mesmo que uma operação de Transação esteja em progresso no momento.
Transações (Transactions)
Transações são geralmente utilizadas quando um Applet necessitar que vários campos e objetos diferentes devem ser atualizados de maneira atômica por exemplo um Applet Moedeiro deve realizar as seguintes operações:
- Incrementar o número de transações.
- Creditar ou Debitar o montante de Crédito.
- Gravar um Log contento terminal, data, hora, etc.
Mesmo com a atomicidade garantindo que valores sejam restaurados, o número de transação se torna incoerente pois já foi incrementado antes da falha ocorrer, com isso temos um corrompimento na estrutura de dados do cartão.
Com isso você pode facilmente imaginar um corrompimento mais severo, como por exemplo o número de transação e o valor do crédito ser atualizado, porém no momento em que um dos elementos do Log estiver sendo atualizado uma falha ocorrer.
Para casos críticos como este em que se é vital que dados distintos mantenham uma sincronia coerente a tecnologia Java Card provê um mecanismo similar ao usados em banco de dados relacionais (RDBMS) baseado no conceito begin, commit e rollback.
Commit Transaction
Commit Transaction
Uma transação é iniciada invocando-se o método JCSystem.beginTransaction e termina ao se usar o método JCSystem.commitTransaction.
//Inicia Transação JCSystem.beginTransaction(); //Operações ... //Finaliza Transação JCSystem.commitTransaction();Todas as operações de atualizações de campos e objetos persistentes, tem a natureza temporária e em caso de falhas os dados anteriores não serão perdidos, todas as atualizações serão gravadas e garantidas após a invocação do método commitTransaction.
Abort Transaction
Transações podem ser abortadas tanto pelo Applet quanto pelo JCRE. Para o caso de o Applet encontrar uma falha interna seja qual for a natureza, ele pode expressamente cancelar toda a transação invocando o método JCSystem.abortTransaction, todas as alterações serão descartadas, isso é similar ao rollback dos RDBMS.
Caso esse método seja invocado fora de uma transação o JCRE lançará uma exceção TransactionException.
Caso uma transação não seja explicitamente terminada pelo commitTransaction o JCRE automaticamente invocará o método abortTransaction.
Caso ocorra uma das falha de perda de alimentação, erro computacional, reset de cartão, etc. Enquanto uma transação está ocorrendo, na próxima vez em que o cartão for alimentado o JCRE automaticamente utilizará um rollback especial restaurando todos os dados anteriores dos campos e objetos envolvidos durante a transação e toda a memória temporária utilizada será liberada, evitando assim o Memory Leak.
Transações Aninhadas
Java Cards não suportam transações aninhadas, isso que dizer caso uma Classe tenha invocado o beginTransaction e durante esse processo, uma outra Classe envolvida também invocar o beginTransaction o JCRE lançará uma exceção TransactionException.
Uma Classe pode descobrir se uma transação está em execução invocando o método JCSystem.transactionDepth, esse método retornará 1 caso uma transação estiver em progresso e 0 caso contrário.
Capacidade de uma Transação
Para suportar o rollback de transações não cometidas o JCRE mantém um commit buffer onde o conteúdo original dos campos são armazenados antes do commit.
Obviamente quanto maior as operações contidas no bloco de transação, maior será o consumo do commit buffer.
Porém o tamanho desse buffer varia de uma implementação para outra, dependem também da quantidade de memória disponível no cartão. No geral, o commit buffer alocado pela implementação do JCRE é grande o suficiente para atender a necessidade da maioria dos Applets, commit buffers costumam não excedem algumas dezenas de bytes.
Como você já deve estar acostumado com as limitações de um Java Card, já deve ter percebido o quão criterioso deverá ser ao usar esse recurso, apenas em blocos de dados críticos e o menor possível.
Felizmente o JCSystem fornece dois métodos que ajudam o Applet a determinar qual a capacidade do commit buffer disponível em determinada implementação do JCRE. Isso quer dizer que cabe a você calcular a quantidade de dados que um bloco de transação utilizará e testar se o commit buffer o atenderá em determinado cartão.
O seguinte método JCSystem.getMaxCommitCapacity retorna o número total de bytes contido no commit buffer.
E o método JCSystem.getUnusedCommitCapacity retorna o número de bytes disponíveis para uso no commit buffer.
Adicionalmente ainda temos o overhead causado pelas operações dentro do bloco de transações, imaginem o seguinte cenário:
- Variavel Persistente A possui o valor 1
- Variavel Persistente B possui o valor 1
- Applet Invoca beginTransaction
- A = 2 ( Valor 1 é armazenado no commit buffer)
- B = 2 ( Valor 1 é armazenado no commit buffer)
- A = A + B (Valor 2 da variavel A é armazenado no commit buffer)
- Applet Invoca commitTransaction
Por fim caso o espaço do commit buffer termine durante um processo de Transação o JCRE lançará um TransactionException.
TransactionException
O JCRE lançará essa exceção quando certos tipos distindo de problemas ocorrerem, TransactionException é uma subclasse de RuntimeException, sendo assim ele provê uma das razões que provocou o lançamento da exceção, são elas:
- IN_PROGRESS - beginTransaction invocado quando uma operação de Transação já esta em progresso.
- NOT_IN_PROGRESS - commitTransaction ou abortTransaction invocado sem que uma Transação esteja em progresso.
- BUFFER_FULL - commit buffer sem espaço suficiente para realizar operação.
- INTERNAL_FAILURE - Erro interno do mecanismo de transação.
Bem, isso foi uma explicação detalhada dos funcionamentos da Atomicidade e Transação, características poderosas do Java Card, não escreverei um programa de testes, pois não existe maneira eficiente de testar esses mecanismos, pois julgo impossível saber quando o cartão está escrevendo o campo ou os campos em uma transação e nesse exato momento retirar o cartão da leitora. A mim e a você resta apenas saber que esses mecanismos existem e em caso de falhas feche seu olhos e acredite que eles irão funcionar.
Um Grande Abraço a Todos e Até a Próxima!
Um Grande Abraço a Todos e Até a Próxima!
Nenhum comentário:
Postar um comentário
Observação: somente um membro deste blog pode postar um comentário.