Calypte em aplicações Java

Calypte é uma ótima opção de cache para aplicações Java. Ele é extremamente rápido, trabalha bem com pouca memória, permite o armazenamento de dados em memória secundária e tem suporte transacional.

Instalação

O Calypte pode ser instalado usando o Maven ou fazendo o download dos binários e configurando-o no classpath da aplicação.

Se for utilizado o Maven, deve ser informado no pom.xml:

<repositories>
    <repository>
        <id>calypte-repo</id>
        <name>Calypte repository.</name>
        <url>https://calypte.sourceforge.io/maven/2</url>
    </repository>
</repositories>

...

<dependency>
	<groupId>calypte</groupId>
	<artifactId>jcalypte</artifactId>
	<version>1.0.2.0</version>
</dependency>

Manipulação de dados

As operações no cache são feitas com o uso da classe CalypteConnection. Ela fica localizada no pacote calypte e é obtida a partir de uma instância da CalypteConnectionPool.

CalypteConnection possui os seguintes métodos:

public interface CalypteConnection {
    
	void close() throws CacheException;
    
	boolean isClosed();
    
	boolean replace(
	String key, Object value, long timeToLive, long timeToIdle) throws CacheException;
    
	boolean replace(
	String key, Object oldValue, 
	Object newValue, long timeToLive, long timeToIdle) throws CacheException;
	
	Object putIfAbsent(
	String key, Object value, long timeToLive, long timeToIdle) throws CacheException;

	boolean set(
	String key, Object value, long timeToLive, long timeToIdle) throws CacheException;
	
	boolean put(String key, Object value, long timeToLive, 
	long timeToIdle) throws CacheException;
    
	Object get(String key, boolean forUpdate) throws CacheException;

	Object get(String key) throws CacheException;
    
	boolean remove(
	String key, Object value) throws CacheException;
    
	boolean remove(String key) throws CacheException;
    
	void setAutoCommit(boolean value) throws CacheException;
    
	boolean isAutoCommit() throws CacheException;
    
	void commit() throws CacheException;
    
	void rollback() throws CacheException;
    
	String getHost();

	int getPort();
    
}
  • close(): fecha a conexão com o servidor;
  • isClosed(): verifica se a conexão está fechada;
  • replace(): substitui o valor associado à chave somente se ele existir;
  • replaceValue(): substitui o valor associado à chave somente se ele for igual a um determinado valor;
  • putIfAbsent(): associa o valor à chave somente se a chave não estiver associada a um valor;
  • put(): associa o valor à chave;
  • set(): associa o valor à chave somente se a chave não estiver associada a um valor;
  • get(): obtém o valor associado à chave bloqueando ou não seu acesso as demais transações;
  • remove(): remove o valor associado à chave;
  • removeValue(): remove o valor associado à chave somente se ele for igual a um determinado valor;
  • setAutoCommit(): define o modo de confirmação automática;
  • isAutoCommit(): obtém o estado atual do modo de confirmação automática;
  • commit(): confirma todas as operações da transação atual e libera todos os bloqueios detidos por essa conexão;
  • rollback(): desfaz todas as operações da transação atual e libera todos os bloqueios detidos por essa conexão;
  • getHost(): obtém o endereço do servidor;
  • getPort(): obtém a porta do servidor.

A CalypteConnectionPool faz o gerenciamento e provê as conexões com o cache. Ele mantém uma certa quantidade de conexões ativas e limita a criação de novas conexões utilizando as conexões atualmente ativas. Isto permite uma melhor utilização dos recursos.

CalypteConnectionPool possui os seguintes métodos:

public class CalypteConnectionPool {
    
	public CalypteConnection getConnection() throws CacheException {...}

	public CalypteConnection tryGetConnection(long l, 
	TimeUnit tu) throws CacheException {...}
    
	public void shutdown() {...}
				
}
  • getConnection(): obtém uma conexão;
  • tryGetConnection(): tenta obter uma conexão esperando um determinado período de tempo;
  • shutdown(): destrói o pool de conexões;
CalypteConnectionPool pool = new CalypteConnectionPool("localhost", 1044, 1, 50);
CalypteConnection con = null;
try{
	con = pool.getConnection();
	...
	con.put(key, value, 0, 0);
}
finally{
	if(con != null){
		con.close();
	}
}

Também é possível criar uma conexão direta com o cache. Nesse caso, ela não será gerenciada!

CalypteConnection con = new CalypteConnectionImp(SERVER_HOST, SERVER_PORT);
...
con.close();

Adicionando itens

São oferecidos vários métodos para inserir um item no cache. Cada um com sua particularidade.

Método put

O método put associa um valor a uma chave, mesmo que ela exista. Retorna true, se o valor for substituído, ou false, se não existir um valor associado à chave.

if(con.put(key, value)){
    System.out.println("replaced");
}
else{
    System.out.println("stored");
}

Método replace

O método replace substitui o valor associado à chave somente se ele existir. Ele retorna true, se o valor for substituído, ou false, se o valor não for armazenado.

if(con.replace(key, value)){
    System.out.println("replaced");
}
else{
    System.out.println("not stored");
}

Também é possível substituir o valor associado à chave somente se ele for igual a um determinado valor.

if(con.replace(key, oldValue, value)){
    System.out.println("replaced");
}
else{
    System.out.println("not stored");
}

Método putIfAbsent

O método putIfAbsent associa o valor à chave somente se a chave não estiver associada a um valor. Retorna o valor associado à chave ou null, se não existir um valor associado à chave. Esse método tem uma particularidade. Quando existe um valor associado à chave, o mesmo é retornado, mas será lançada uma exceção se ele expirar no momento em que for recuperado.

try{
    Object currentValue = con.putIfAbsent(key, value);
    if(currentValue == null){
        System.out.println("stored");
    }
    else{
        System.out.println("not stored");
    }
}
catch(CacheException $e){
    if(e.getCode() == 1030){
        //o valor atual expirou
    }
    throw e;
}

Método set

O método set associa o valor à chave somente se a chave não estiver associada a um valor. Ele retorna true, se o valor for associado à chave, ou false, se ele for descartado.

if(con.set(key, value)){
     System.out.println("stored");
}
else{
     System.out.println("not stored");
}

Obtendo itens

Método get

Um valor é obtido com o uso do método get. Ele retorna o valor associado à chave ou null, se não existir um valor associado.

Object value = con.get(key);

if(value != null){
     System.out.println("value exists");
}
else{
     System.out.println("value not found");
}

Removendo itens

São oferecidos vários métodos para remover um item do cache.

Método remove

O método remove apaga o valor associado à chave. Ele retorna true, se o valor for removido, ou false, se ele não existir.

if(con.remove(key)){
    System.out.println("removed");
}
else{
    System.out.println("not found");
}

Também é possível remover o valor associado à chave somente se ele for igual a um determinado valor.

if(con.remove(key, value)){
    System.out.println("removed");
}
else{
    System.out.println("not found");
}

Iniciando uma transação

Uma transação é iniciada com o uso do método setAutoCommit() com o parâmetro igual a false e finalizada com o método commit(), rollback() ou setAutoCommit() com o parâmetro true.

Método setAutoCommit

O método setAutoCommit() define o modo de confirmação automática. Se o modo de confirmação automática estiver ligado, todas as operações serão tratadas como transações individuais. Caso contrário, as operações serão agrupadas em uma transação que deve ser confirmada com o método commit() ou descartadas com o método rollback. Por padrão, cada nova conexão inicia com o modo de confirmação automática ligada.

//inicia a transação desligando o modo de confirmação automática.
con.setAutoCommit(false);
...
//confirma todas as operações ligando o modo de confirmação automática.
con.setAutoCommit(true);

Método commit

O método commit() confirma todas as operações da transação atual e libera todos os bloqueios detidos pela atual sessão.

//inicia a transação.
con.setAutoCommit(false);
...
//confirma todas as operações.
con.commit();

Método rollback

O método rollback() desfaz todas as operações da transação atual e libera todos os bloqueios detidos pela atual sessão.

try{
    //inicia a transação.
    con.setAutoCommit(false);
    ...
    //confirma todas as operações.
    con.commit();
}
catch(Exception e){
    //Desfaz todas as operações.
    con.rollback();
}

Evitando a leitura fantasma e leitura não repetitiva

Para resolver o problema de leitura fantasma e leitura não repetitiva, é oferecida a opção de bloquear um determinado item no momento de sua seleção. A opção é o parâmetro forUpdate do método get.

No exemplo abaixo, depois que o método get() é executado, o item key fica bloqueado até que o método commit() ou rollback() seja executado.

try{
    //inicia a transação.
    con.setAutoCommit(false);
    //bloqueia o item key.
    value = con.get(key, true);
    if(value != null && value.equals(value2)){
        //remove o item key se existir e for igual ao valor 'val'
        con.remove(key);
    }
    //confirma todas as operações.
    con.commit();
}
catch(Exception e){
    //Desfaz todas as operações.
    con.rollback();
}