Objetivo


Esse documento tem como objetivo deixar claro o que representa a CMOS para o Storex e como devemos fazer futuras customizações nela.


Conceito


CMOS representa uma memória não volátil, ou seja persistente. Normalmente, ela é utilizada por aplicações para guardar valores essenciais que são necessários para a restauração do estado da aplicação após a finalização da mesma, seja por motivos esperados ou não.

No Storex Cusom ela é utilizada para armazenar informações que serão utilizadas ao longo de uma operação, por exemplo uma operação de venda, ou até mesmo ao longo do dia. Neste caso podemos citar como exemplo, informações sobre os totais do PDV, onde as mesmas serão utilizadas nos processos de fechamento de operador e encerramento de dia.


Arquitetura


GerenciadorCMOS

É a classe que permite gravação e leitura do conteúdo da memória CMOS. Ela gerencia o acesso a CMOS (dispositivo físico), mantendo na memória os objetos passados pelo componente à cmos para fazer com que a recuperação dos mesmos ocorra de forma mais rápida. Essa classe não deve ser especializada, ou seja, não é aconselhável criar uma classe de mesmo nome dentro da mesma estrutura de pacote. Caso isso seja feito, corre-se o risco de perder alguma implementação já realizada e até mesmo futuras evoluções que venham a ser feitas no kernel do sistema.

As leituras ao dispositivo físico serão sempre feitas pelo espelho da CMOS (cópia em memória RAM), promovendo assim um aumento de performance. Para isso, o método inicializaDados() é executado na inicialização da aplicação, para carregar toda a informação que está na CMOS física para o espelho da CMOS. As escritas serão sempre feitas em bloco, ou seja, toda a CMOS será gravada (descarregada da imagem de memória), para evitar problemas de queda de energia durante uma gravação. Diminuindo sensivelmente a possibilidade de corromper o arquivo.


Formas de acesso



Chave de acesso

Para armazenar um objeto no dispositivo físico é preciso definir uma chave para ele. Esta é formada por um conjunto de caracteres, representando o nome do objeto.

Ao lado podemos ver um exemplo de chave e a informação na CMOS que ela representa.

Exemplos de chave de acesso
/**
* Constante que representa o uso do cupom troca presente.
*/
private static final String USA_CUPOM_TROCA_PRESENTE = "usTrPr";


/**
*  Indica que uso do cupom troca presente.
*/
private boolean usaCupomTrocaPresente = false;

Carregando a informação

Ao lado podemos ver o trecho de código no método inicializaDados() que tem o objetivo de carregar na memória a informação que está armazenada no dispositivo físico.

Através do método leDados() da classe CMOS, passando a chave do objeto, a informação que está gravada no arquivo será devolvida e carregada em memória.

Carregando informação na memória
try {
	usaCupomTrocaPresente = ((Boolean) cmos.leDados(USA_CUPOM_TROCA_PRESENTE)).booleanValue();
} catch (ExcecaoNaoLocal ex) {
	if (!(ex.getExcecaoOriginal() instanceof ExcecaoObjetoInexistente)) {
		rollbackGeral(beginList);
		CSIDebug.println(ex);
		throw ex;
	}
}

Acesso aos objetos

Cada atributo definido deve possuir os métodos leitura e escrita, com suas respectivas implementações.

Ao lado temos um exemplo de implementação do método de leitura para o atributo usaCupomTrocaPresente, usado no exemplo mais acima. Podemos observar que o valor retornado é o que está em memória. Ou seja, não acessa o dispositivo físico. Por isso que é importante o carregamento da informação na memória, como demonstrado no exemplo acima.

Em seguida temos a implementação do método set para este mesmo atributo, ou seja, o método de escrita. Alguns pontos importantes:

Antes de gravar a informação na CMOS, é preciso chamar o método beginTransaction(). Este coloca a CMOS no estado de transação, preparando a mesma para o processo de escrita.

Em seguida é executado o método colocaDados(), passando a chave (o nome que identifica o objeto na cmos) que será usada e o objeto a ser gravado. Caso seja passado um valor nulo, o mesmo será apagado da cmos.

O passo seguinte é a confirmação com a execução do método commitTransaction(). Este efetiva todas as alterações feitas no objeto após a execução do método beginTransaction().

Por último temos o valor sendo atualizado na memória, para que o método que retorna a informação fique com o valor atualizado.

Exemplos de métodos de acesso
public boolean isUsaCupomTrocaPresente() {
	return usaCupomTrocaPresente;
}

public void setUsaCupomTrocaPresente(boolean isUsaCupomTrocaPresente) {
	try {
		if (!fezBegin) {
			beginTransaction();
		}
		colocaDados(USA_CUPOM_TROCA_PRESENTE, Boolean.valueOf(isUsaCupomTrocaPresente));
		if (fezBegin) {
			commitTransaction();
		}
	} catch (ExcecaoNaoLocal e) {
		try {
			rollbackTransaction();
		} catch (Exception ex) {
		}
	}

	this.usaCupomTrocaPresente = isUsaCupomTrocaPresente;
}

Trabalhando com informações complexas

Como a cmos é um arquivo e o mesmo tem um limite de armazenamento, quando trabalhamos com uma informação que venha a ocupar uma quantidade maior de espaço, é importante fazer o armazenamento num arquivo separado. Esses arquivos serão armazenados dentro de /p2k/bin/cmos.

Ao lado temos um exemplo, onde a informação será trabalhada num arquivo a parte. O primeiro bloco de código é a definição da chave e o atributo correspondente.

Em seguida temos a informação sendo carregada na memória, durante execução do método inicializaDados(). Aqui vamos observar o uso do método leObjetoDoArquivo(), passando a chave como parâmetro. Nesse caso a informação está sendo carregada de um arquivo específico.

No terceiro bloco de código temos os métodos de acesso get e set para esse atributo. A diferença está no método set, onde ele faz uso do colocaObjetoArquivo(). Este colocará o objeto em um arquivo serializável. Caso o objeto seja nulo, o arquivo será removido da pasta /p2k/bin/cmos.









Definindo chave e atributo
private static final String TRANS_CANC_ANULA_DEV_TROCA_EXTENSIVEL = "tcadt";
private TransacaoCancAnulaDevTrocaExtensivel transacaoCancAnulaDevTrocaExtensivel = null;

Carregando informação na memória
try {
	this.transacaoCancAnulaDevTrocaExtensivel = (TransacaoCancAnulaDevTrocaExtensivel)  this.leObjetoDoArquivo(TRANS_CANC_ANULA_DEV_TROCA_EXTENSIVEL);
} catch (ExcecaoObjetoInexistente e) {
	CSIDebug.println(e);
	if (!(e.getExcecaoOriginal() instanceof ExcecaoObjetoInexistente)) {
		rollbackGeral(beginList);
		throw e;
	}
}

Métodos de acesso
public TransacaoCancAnulaDevTrocaExtensivel getTransacaoCancAnulaDevTrocaExtensivel() {
	return transacaoCancAnulaDevTrocaExtensivel;
}

public void setTransacaoCancAnulaDevTrocaExtensivel(TransacaoCancAnulaDevTrocaExtensivel trans) throws ExcecaoNaoLocal {
	boolean fezBeginLocal = false;
	if (!fezBegin) {
		beginTransaction();
		fezBeginLocal = true;
	}
	colocaObjetoArquivo(TRANS_CANC_ANULA_DEV_TROCA_EXTENSIVEL, trans);
	this.transacaoCancAnulaDevTrocaExtensivel = trans;
	
	if (fezBeginLocal) {
		commitTransaction();
	}
}

Criação de novos atributos


Ao criarmos novos atributos na CMOS, precisamos considerar que ela é um dispositivo físico e possui limitação de tamanho. Por conta disso, é importante avaliar outras alternativas que não seja o uso da cmos. Quando realmente necessário, é aconselhável utilizar a estratégia de criarmos atributos em novos arquivos, como demonstrado no exemplo mais acima. Além disso será preciso criar uma nova classe que vai herdar de com.csi.components.cmos.pos.GerenciadorCMOS. Isso é necessário, pois a especialização desta classe (criar uma classe de mesmo nome e dentro do mesmo pacote) é profundamente desaconselhável. Caso isso seja feito, todos os atributos disponibilizados pelo Kernel do Storex Custom serão perdidos.

Para criar essa classe nova é preciso seguir as orientações que vamos demonstrar mais abaixo.


Criando nova classe

Para a customização de novos atributos na CMOS, sem perder os atributos já existentes, o primeiro passo é criar uma classe chamada GerenciadorCMOSCustom dentro do pacote com.linx.storex.custom.cmos. Essa classe deve herdar de com.csi.components.cmos.pos.GerenciadorCMOS.

Ao lado, temos um exemplo da implementação dessa classe nova.















Agora vamos demonstrar como criar um novo atributo do tipo boolean na classe GerenciadorCMOSCustom. Importante observar que o método inicializaDados() é responsável por chamar o mesmo método da classe mãe, para que seus atributos sejam carregados na memória.

implementação de GerenciadorCMOSCustom
package com.linx.storex.custom.cmos;

import com.csi.components.cmos.pos.GerenciadorCMOS;
import com.csi.components.interfaceDal.ConcentradorCadastrosComponente;
import com.csi.devices.CMOS;
import com.csi.services.exceptions.ExcecaoLocal;
import com.csi.services.exceptions.ExcecaoNaoLocal;
import com.csi.services.exceptions.ExcecaoObjetoInexistente;

public class GerenciadorCMOSCustom extends GerenciadorCMOS {

	public GerenciadorCMOSCustom(CMOS novaCmos, ConcentradorCadastrosComponente concentrador) {
		super(novaCmos, concentrador);
	}

	@Override
	public void inicializaDados() throws ExcecaoNaoLocal {
		super.inicializaDados();
	}
	
}

GerenciadorCMOSCustom com um atributo novo
package com.linx.storex.custom.cmos;

import com.csi.components.cmos.pos.GerenciadorCMOS;
import com.csi.components.interfaceDal.ConcentradorCadastrosComponente;
import com.csi.devices.CMOS;
import com.csi.services.exceptions.ExcecaoLocal;
import com.csi.services.exceptions.ExcecaoNaoLocal;
import com.csi.services.exceptions.ExcecaoObjetoInexistente;
import com.csi.util.CSIDebug;

public class GerenciadorCMOSCustom extends GerenciadorCMOS {

	private static final String IS_NOVA_CMOS = "newCmos";
	private boolean novaCmos;
	
	public GerenciadorCMOSCustom(CMOS novaCmos, ConcentradorCadastrosComponente concentrador) {
		super(novaCmos, concentrador);
	}

	@Override
	public void inicializaDados() throws ExcecaoNaoLocal {
		super.inicializaDados();
		
		try {
			novaCmos = ((Boolean)super.cmos.leDados(IS_NOVA_CMOS)).booleanValue();
		} catch(ExcecaoNaoLocal e) {
			novaCmos = false;
		    CSIDebug.println(e);
			if (!(e.getExcecaoOriginal() instanceof ExcecaoObjetoInexistente)) {
				rollbackGeral(beginList);
				throw e;
			}
		}
	}
	
	public boolean isNovaCMOS() {
		return novaCmos;
	}
	
	public void setNovaCmos(boolean novaCmos) throws ExcecaoNaoLocal {
		if (!fezBegin) {
			beginTransaction();
		}
		
		colocaObjetoArquivo(IS_NOVA_CMOS, new Boolean(novaCmos));
		this.novaCmos = novaCmos;
		
		if (fezBegin) {
			this.commitTransaction();
		}
	}
}

Fazendo uso da nova classe

Ao lado podemos ver a forma de obter a instância da nova classe GerenciadorCMOSCustom e acessar tanto atributos novos quanto os que são fornecidos pelo Storex Standard.

Usando o GerenciadorCMOSCustom
Componente componente = Componente.getInstance();
PDV pdv = (PDV) componente;
GerenciadorCMOSCustom cmosCustom = (GerenciadorCMOSCustom) pdv.getPerifericos().getCmos();


cmosCustom.setNovaCmos(true);


int diferenciadorChaveCmos = cmosCustom.getDiferenciadorChave();
ConjuntoTotalOperador conjuntoTotaisOperador = cmosCustom.getConjuntoTotalOperador();




  • Sem rótulos