Objetivo


Esse documento tem como objetivo mostrar, através de exemplos práticos, a forma como devemos implementar as classes que são responsáveis por fazer a persistência dos dados, na camada de comunicação com o banco de dados relacional.


Arquitetura


O módulo responsável por fazer a persistência dos dados no banco relacional é o Storex-int-trans. Este é o serviço que roda na retaguarda da operação e que recebe as mensagens dos componentes que estão nas lojas, para cada operação realizada. Essas mensagens trafegam objetos com os dados das transações.

Foi adotado o padrão de projeto chamado Chain of Responsibility, ou cadeia de responsabilidade. Este padrão de projeto possui a característica de evitar o acoplamento do remetente de uma transação ao seu receptor, ao dar a mais de um objeto a oportunidade de tratar essa transação. Foi desenvolvido um encadeamento de objetos receptores, onde cada um deles vai passando a transação ao longo da cadeia, até que um objeto esteja preparado para processar essa transação.

Para entendermos melhor como o mecanismo funciona, precisamos conhecer algumas classes que são utilizadas no processo.

ObjetoCadastro

As transações são classes que herdam de com.csi.info.transacoes.Transacao e esta herda de ObjetoCadastro. Esta, por sua vez, é a classe que define genericamente todos os objetos do sistema que serão armazenados diretamente em um banco de dados.

HandlerObject2Db

Classe abstrata que define as operações que devem ser implementadas por objetos tratadores, ou seja os Handlers, que realizam mapeamento entre um objeto de cadastro do Storex Custom para o banco de dados relacional. Essas classes são orquestradas pelo com.linx.services.dal.relacional.transacoes.RepositorioTransacoesRelacional. Esta tem a função de encaminhar a transação para a classe Handler responsável por atualizar as informações no banco de dados.

Classes Handlers

São as classes que herdam de HandlerObject2Db e que implementam o método executeObject2DB(). Este é o método que recebe um ObjetoCadastro e faz o mapeamento desse objeto para o banco de dados relacional. Nele é onde efetivamente implementa-se a operação que fará a inclusão ou atualização dos dados no banco. A implementação utiliza o JDBC, onde este é API Java que fornece as classes e interfaces na qual possibilitam a conexão através de um driver específico do banco de dados utilizado.


Principais Handlers



O Storex Custom fornece uma vasta quantidade de implementações de Handlers, que realizam as operações de insert, update ou delete em diversas tabelas que armazenam as transações realizadas nos PDVs. Transações de venda, anulações, entrada de operador, fechamento de caixa, entre outras. Os handlers são organizados em pastas que tenham relação com o tipo de transação.

No projeto storex-int-trans, podemos encontrar todos os Handlers implementados até o momento. Para o cliente desenvolver suas próprias classes handlers, será disponibilizado no repositório o projeto int-trans-NOME_CLIENTE.


Criação de um novo Handler


Vamos demonstrar através de um exemplo a forma como uma transação nova será inserida na cadeia de handlers para que as informações sejam persistidas no banco relacional.


Uma nova transação

Vamos criar uma nova transação que será representada pela classe TransacaoCustom. Lembrando que você pode escolher um nome para a sua classe, que traduza da melhor forma possível, o objetivo da transação que está sendo criada.

A implementação ao lado é apenas um exemplo, portanto é uma transação com apenas uma informação.

TransacaoCustom
public class TransacaoCustom extends Transacao {

	private static final long POS_LONG_CODIGO_GENERICO = 0;
	
	private boolean[] atributosBoolean;
    private long[] atributosLong;
	private Object[] atributosObject;
	
	public TransacaoCustom(int numero, String pdv, Data data, String loja) 
			throws ExcecaoStringInvalido, ExcecaoDataInvalida {
				
		super(numero, pdv, data, loja);
		inicializaArrays();
	}

	private void inicializaArrays() {
		// inicializar os Arrays de boolean, long e object de acordo com a necessidade
		atributosLong = new long[1];
	}
	
	public long getCodigoGenerico() {
		if (this.atributosLong.length > POS_LONG_CODIGO_GENERICO) {
			return atributosLong[POS_LONG_CODIGO_GENERICO];
		}
		return 0L;
	}
	
	public void setCodigoGenerico(long codigoGenerico) {
		if (this.atributosLong.length > POS_LONG_CODIGO_GENERICO) {
			this.atributosLong[POS_LONG_CODIGO_GENERICO] = codigoGenerico;
		}
	}

}

Um novo Handler

Ao lado temos a criação do Handler que fará o tratamento para a transação criada acima, TransacaoCustom.

O Handler precisa herdar da classe HandlerObject2DB e disponibilizar um construtor padrão, de acesso público. Além disso a persistência é feita utilizando-se o JDBC nativo do Java.

É fundamental que o método executeObject2DB seja implementado seguindo o padrão mostrado no exemplo. Este recebe o objeto correspondente à transação e a conexão com o banco.

HandlerIncluiTransacaoCustom
package com.linx.services.dal.relacional.transacoes.handlers.custom;


public class HandlerIncluirTransacaoCustom extends HandlerObject2Db {
	
	/**
	 * Instancia do preenchedor da chave.
	 */
	private PreeencheValoresChaveTransacaoWrapper preenchedorChave;
	
	/**
	 * Construtor com acesso restrito do handler
	 */
	public HandlerIncluiTransacaoCustom() {
		preenchedorChave = PreeencheValoresChaveTransacaoWrapper.getMyInstance();
	}

	/**
	 * Assinatura que especifica a operação de mapear parte de uma objeto de
	 * cadastro para o banco de dados relacional
	 *
	 * @param objetoPersistente O objeto que deve ser persistido em forma de
	 *                          registros no banco de dados relacional.
	 * @param conexaoBanco      A conexão com o banco de dados para que possa ser
	 *                          realizadas as operações de acesso ao banco de dados
	 *                          relacional
	 * @return O template usado no processamento do objeto para o banco de dados
	 */
	public final void executeObject2DB(ObjetoCadastro transacaoPersistente, Connection conexaoBanco)
			throws ExcecaoErroCAD, ExcecaoDadoInvalido, ExcecaoObjetoInexistente {
				
		if (!(transacaoPersistente instanceOf TransacaoCustom)) {
			// Se a transação não for uma TransacaoCustom a execução do método será interrompida
			return;
		}
		
		PreparedStatement pstmt = null;
		String templateCorrente = null;
		
		try {
			TransacaoCustom transacao = (TransacaoCustom) transacaoPersistente;

			pstmt = conexaoBanco.prepareStatement(templateCorrente = GerenciadorTemplateStatement
					.getTemplate(IntConstantesDalTransacao.INSERT_TRANSACAO_CUSTOM));
					
			pstmt = preenchedorChave.setaValoresChave(pstmt, (ChaveTransacao) transacao.getChave(), 1);
			
			// a chave da transação utiliza os índices de 1 a 4 
			// do prepareStatement. Por isso que continua a partir do índice 5.
			pstmt.setInt(5, transacao.getCodigoGenerico());
			
			pstmt.executeUpdate();
			
		} catch (SQLException sqle) {
			throw new ExcecaoErroCAD(new ExcecaoLocal("", "", templateCorrente, sqle));
		} finally {
			closeStatement(pstmt);
		}
				
	}
}

XML de configuração

Um arquivo no formato XML que contém uma lista de transações e seus respectivos handlers, os quais serão carregados durante a inicialização do sistema. Esse arquivo pode ser encontrado na pasta bin do integrador de transações (/int-trans-NOME_CLIENTE/bin).

Para adicionar novos itens, é preciso seguir o modelo ao lado, onde TransactionHandler se refere a um novo item da lista, que contem respectivamente, o nome da transação (TransactionName) e a
lista de handlers (handlerList) por tipo de operação (Incluir, Alterar e Excluir).

A tag <transactionName> deve ser preenchida com o tipo correspondente à transação que foi enviada pelo PDV, sem considerar as classes base.
Um exemplo. Considere a classe TransVendaComPedidoExtensivel que herda de TransacaoVenda. O PDV envia uma transação do tipo TransVendaComPedidoExtensivel para o integrador de transações. Para que novos handlers sejam reconhecidos, no xml a tag <transactionName> deve ser preenchida com o tipo TransVendaComPedidoExtensivel e não com a classe base.

Para cada, item da lista de handlers, é necessário informar o caminho completo da classe, ou seja, pacote + nome da classe.

Configuração dos Handlers
<TransactionHandlerList>

	<TransactionHandler>
		<transactionName>TransacaoCustom</transactionName>
		<handlerListIncluir>
			<string>com.linx.services.dal.relacional.transacoes.handlers.util.HandlerIncluirTransacaoCustom</string>
		</handlerListIncluir>
		
		<handlerListAlterar>
			<string>com.linx.services.dal.relacional.transacoes.handlers.util.HandlerAlterarTransacaoCustom</string>
		</handlerListAlterar>
		
		<handlerListExcluir>
			<string>com.linx.services.dal.relacional.transacoes.handlers.util.HandlerExcluirTransacaoCustom</string>
		</handlerListExcluir>
	</TransactionHandler>	
	
</TransactionHandlerList>

Alterando uma Transação


Para evitar a cópia de classes Handlers, com o intuito de evitar a perda das evoluções que venham a ser realizadas no kernel do Storex Custom, foi seguido a estratégia de implementar um handler de alteração que será executado logo após o handler de inclusão. Mais abaixo veremos como fica a configuração no xml.


Customizando Transação de Venda

Para customizar uma transação existente, o Storex Custom fornece a classe abstrata CustomEntity. Portanto é necessário implementar uma nova classe que herda de CustomEntity e nela vamos incluir os novos métodos get e set que darão acesso às novas colunas criadas no banco de dados relacional. Podemos ver mais detalhes de como implementar a CustomEntity no documento Criação do Entities.

Ao lado podemos ver como fica a configuração no XML, onde os handlers incluídos dentro da cadeia de execuções, associadas ao tipo de transação TransVendaComPedidoExtensivel, serão processados após a sequencia de handlers existentes no Storex Custom. Portanto, como os handlers já existentes fazem os inserts nas tabelas de transações de vendas, o handler que chamamos de HandlerTransacaoVendaAtualizarCustomEntity, deverá fazer uma operação de update com os novos atributos da CustomEntity implementada na Transação de venda.


Configurando Handler para uma transação existente
<TransactionHandlerList>

	<TransactionHandler>
		<transactionName>TransVendaComPedidoExtensivel</transactionName>
		<handlerListIncluir>
			<string>com.linx.services.dal.relacional.transacoes.handlers.util.HandlerTransacaoVendaAtualizaCustomEntity</string>
		</handlerListIncluir>
		
	</TransactionHandler>	
	
</TransactionHandlerList>



  • Sem rótulos