Jape (Persistência de dados)
Introdução
O Jape é o framework de persistência de dados da Sankhya, ele disponibiliza métodos para consulta, inserção, deleção e alteração de registros em instâncias de dados previamente mapeadas. Na maioria dos casos ele é o principal recurso para manipulação de dados no banco, mas também é possível usar querys nativas (NativeSql) para essa finalidade.
O Jape provê recursos para mapeamento de classes Java em tabelas de banco de dados relacionais, além de recursos de consulta e manipulação de dados, evitando que o desenvolvedor precise realizar essa tarefas diretamente.
Referência Técnica (Javadoc)
Consulte a especificação de interfaces, classes, construtores, métodos e atributos do Jape:
Controle de sessão
A sessão é um estado de comunicação entre a aplicação e o banco de dados, e consiste em requisições e respostas realizada entre os dois. A sessão é usada para estabelecer uma conexão com o banco de dados, onde os objetos de sessão são projetados para serem instanciados sempre que haja um interação necessária com o banco. Os objetos de sessão não devem ser mantidos constantemente abertos, eles devem ser criados e fechados conforme necessário. A principal função da sessão é fornecer um estado que permita operações de criação, leitura e exclusão de dados em instâncias de entidades mapeadas. O controle se inicia com a sua abertura e é finalizado com o encerramento da sessão.
Abertura da sessão
A abertura da sessão é realizada pelo método JapeSession.open(), sempre que uma sessão é aberta se vincula a um objeto SessionHandle, que gerencia metadados da sessão. A sessão deve ser aberta usando o bloco Try e para fechamento da sessão o bloco Finally .
Fechamento da sessão
O fechamento da sessão é necessário para liberar os recursos atrelados a ela, esse procedimento é realizado com o método JapeSession.close(hnd).
Uma sessão típica deve adotar o seguinte padrão:
SessionHandle hnd = null; // identifica o início de uma sessão.
try {
hnd = JapeSession.open(); // abertura da sessão
hnd.execWithTX( new JapeSession.TXBlock(){
public void doWithTx() throws Exception{
//realiza operações em entidades ou NativeSQL
}
});
} finally {
JapeSession.close(hnd); // fechamento da sessão
}
No exemplo acima foi criado o objeto hnd do tipo SessionHandler acima do bloco try, permitindo assim fechar a sessão sempre que a thread sair do bloco.
Timeout
Especifica o limite de tempo para expiração da sessão, além de evitar que uma sessão cause algum tipo de conflito ou algum deadlock no banco de dados. O TimeOut de sessão pode ser evitado usando métodos específicos.
- setCanTimeout(false) - seta o valor false para que o timeout não ocorra.
SessionHandle hnd = null;
try {
hnd = JapeSession.open();
hnd.setCanTimeout(false); //instrução para evitar o Timeout
hnd.execWithTX( new JapeSession.TXBlock(){
public void doWithTx() throws Exception{
//realiza operações em entidades ou NativeSQL
}
});
} finally {
JapeSession.close(hnd); // fechamento da sessão
}
Controle de transação
Uma transação consiste em uma sequencia de operações realizadas no banco de dados, é considerada uma unidade indivisível de trabalho, onde todas ou nenhuma das ações serão executadas. A transação é associada a uma sessão e têm dois objetivos principais:
-
Fornecer operações no banco de dados, mantendo a integridade dos dados mesmo em casos de falhas.
-
Fornecer isolamento entre operações executados sobre o banco de dados.
Quando a transação é finalizada com sucesso, as modificações correspondentes são salvas (commit).
Porém se uma operação da transação falhar, toda a unidade de trabalho é revertida (rollback)
No Jape há transações automáticas e manuais. A primeira usada para todos os modelos de transação e a segunda em operações curtas no banco de dados (onde cada interação é independente).
Transação Automática
A transação automática é utilizada para qualquer tipo de operação no banco de dados. Ela precisa da anotação @ejb.transaction type="Required", no caso de um serviço.
/**
* @ejb.transaction type="Required"
*/
Transação Manual
A transação manual foi criada para situações de curta operação no banco de dados, onde cada interação é independente. Transações manuais devem adotar a seguinte estrutura:
SessionHandle hnd = null;
try {
hnd = JapeSession.open();
hnd.execWithTX( new JapeSession.TXBlock(){
public void doWithTx() throws Exception{
//realiza operações em entidades ou NativeSQL
}
});
} finally {
JapeSession.close(hnd);
}
Algumas propriedades podem ser associadas à sessão no momento da transação, como as listadas abaixo:
JapeSession.putProperty("usuario_logado", CODUSU);
JapeSession.putProperty("emp_usu_logado", usuVO.getCODEMP());
JapeSession.putProperty("dh_atual", new Timestamp(System.currentTimeMillis()));
JapeSession.putProperty("d_atual", new Timestamp(TimeUtils.getToday()));
JapeSession.putProperty("usuarioVO", usuVO);
JapeSession.putProperty("authInfo", authInfo);
JapeSession.putProperty("modelSession",ModelSessionManager.getSingleton().getSession(authInfo.getAuthenticationID()));
Acesso a dados
O acesso a dados compreende a capacidade do usuário de acessar ou recuperar dados armazenados no banco de dados. O JAPE foi projetado para efetuar esse processo de maneira simples e segura, garantindo assim a integridade dos dados consultados.
Após a abertura de sessão e conexão com o banco de dados inicia-se a coleta de informações. Nessa operação é instanciado um objeto que será o mapeamento do banco de dados feito do dicionário de dados, com o auxilio do método DWF Facade que se define a instância que irá ser trabalhada.
Dependendo da conexão que o usuário fizer, além da sessão é necessário abrir a conexão com o JDBC (iniciando uma sessão). Isso é sempre realizado quando for feito alguma alteração com o banco de dados.
Abaixo são listados métodos para acesso e coleta de dados:
getDefaultValueObjectInstance
Método utilizado para criar um DynamicVO vazio (default). Retorna um DynamicVO para a instância definida. O parâmetro utilizado é apenas o nome da instância.
EntityFacade dwfFacade = EntityFacadeFactory.getDWFFacade();
DynamicVO finVO = (DynamicVO) dwfFacade.getDefaultValueObjectInstance(DynamicEntityNames.FINANCEIRO);
findEntityByPrimaryKeyAsVO
Método utilizado para buscar um registro pela PK. Retorna um DynamicVO para a instância pesquisada. Os parâmetros utilizados são: Nome da instância e um array de objetos com os parâmetros (PK). A ordem dos parâmetros deve ser exatamente a mesma da primakey definida na tabela.
EntityFacade dwfFacade = EntityFacadeFactory.getDWFFacade();
DynamicVO finVO = (DynamicVO) dwfFacade.findEntityByPrimaryKeyAsVO(DynamicEntityNames.FINANCEIRO, new Object[]{nuFin});
findByDynamicFinderAsVO
Método utilizado para buscar uma coleção de registros por um critério personalizado. Retorna uma coleção de DynamicVO. Os parâmetros utilizados são: Nome da instância, critério SQL e um array de objetos com os parâmetros. A ordem dos parâmetros deve ser a mesma utilizada no critério.
EntityFacade dwffacade = EntityFacadeFactory.getDWFFacade();
FinderWrapper finder = new FinderWrapper(DynamicEntityNames.FINANCEIRO, "this.CODPARC = ? AND this.DTVENC > ?", new Object[]{codParc, dtVenc});
Collection<DynamicVO> financeiros = dwfFacade.findByDynamicFinderAsVO(finder);
createEntity
Método utilizado para criar um registro. Retorna um PersistentLocalEntity. Os parâmetros utilizados são: Nome da instância e o DynamicVO correspondente. Este método requer uma transação ativa (controlada pelo container ou manual).
EntityFacade dwfFacade = EntityFacadeFactory.getDWFFacade();
DynamicVO finVO = (DynamicVO) dwfFacade.getDefaultValueObjectInstance(DynamicEntityNames.FINANCEIRO);
finVO.setProperty("DTNEG", dtNeg);
finVO.setProperty("DTVENC", dtVenc);
finVO. setProperty("CODEMP", codEmp);
finVO. setProperty("CODPARC", codParc);
finVO. setProperty("CODTIPOPER", codTipOper);
FfinVO. setProperty("CODTIPTIT", codTipTit);
finVO. setProperty("CODCTABCO", codCtaBco);
finVO. setProperty("VLRDESDOB", vlrDesdob);
dwfFacade.createEntity(DynamicEntityNames.FINANCEIRO, (EntityVO) finVO);
setValueObject
Método utilizado para alterar um registro existente. O parâmetro utilizado é o DynamicVO correspondente. Este método requer uma transação ativa (controlada pelo container ou manual).
EntityFacade dwfFacade = EntityFacadeFactory.getDWFFacade();
PersistentLocalEntity finEntity = dwfFacade.findEntityByPrimaryKey (DynamicEntityNames.FINANCEIRO, new Object[]{nuFi});
DynamicVO finVO = (DynamicVO) finEntity.getValueObject();
finVO. setProperty("CODTIPTIT", codTipTit);
finVO.setProperty("DTVENC", dtVenc);
finEntity.setValueObject((EntityVO) finvo);
removeEntity
Método utilizado para remover um registro pela PK. Os parâmetros utilizados são: Nome da instância e um array de objetos com os parâmetros (PK). A ordem dos parâmetros deve ser exatamente a mesma da primakey definida na tabela. Este método requer uma transação ativa (controlada pelo container ou manual).
EntityFacade dwfFacade = EntityFacadeFactory.getDWFFacade();
dwfFacade.removeEntity(DynamicEntityNames.FINANCEIRO, new Object[{nuFin}];
removeByCriteria
Método utilizado para remover registros por um critério personalizado. Retorna a quantidade de registros removidos. Os parâmetros utilizados são: Nome da instância, critério SQL e um array de objetos com os parâmetros. A ordem dos parâmetros deve ser a mesma utilizada no critério. Este método requer uma transação ativa (controlada pelo container ou manual).
EntityFacade dwfFacade = EntityFacadeFactory.getDWFFacade();
FinderWrapper finder = new FinderWrapper(DynamicEntityNames.FINANCEIRO, "this.CODPARC = ? AND this.DTIVENC >= ?", new Object[]{codParc, dtVenc});
dwfFacade. removeByCriteria(finder);
- Usando JapeWrapper
SessionHandle hnd = null;
try {
hnd = JapeSession.open();
JapeWrapper empresaDAO = JapeFactory.dao(DynamicEntityNames.EMPRESA);
DynamicVO empresa = empresaDAO.findByPK(BigDecimal.ZERO);
}
finnaly {
JapeSession.close(hnd);
}
- Usando NativeSQL
NativeSql sql = new NativeSql(jdbc);
sql.appendSql("SELECT * FROM TSIUSU WHERE CODUSU = :CODUSU");
sql.setNamedParameter("CODUSU", BigDecimal.ZERO);
ResultSet rset = sql.executeQuery();
Entity listener
Os listeners são regras associadas ao Jape pelo mapeamento das entidades e são realizados no dicionário de dados. Cada listener é executado mediante a um evento de inclusão, alteração ou remoção de registro em uma tabela. Os listeners são controlados pelo JAPE e com ele há total controle da sessão e transação, ou seja o usuário tem acesso direto ao dado requisitado ao banco.
Em geral associa-se um listener a cada tabela, mas há casos em que são feitos mais de uma associação, porém não é um processo comum.
Os métodos que podem ser implementados são definidos na interface PersistenceEventListener.java, sendo eles:
public interface PersistenceEventListener extends Serializable {
void afterDelete(PersistenceEvent event) throws Exception; // Executado depois de remover o registro.
void afterInsert(PersistenceEvent event) throws Exception; // Executado depois de incluir o registro.
void afterloadValueObject(PersistenceEvent event) throws Exception; // Executado depois de carregar um VO. Em casos de entidades de somente leitura (readOnly), será executado uma vez por registro em cada transação.
void afterRetrieveValueObject(PersistenceEvent event) throws Exception; // Executado depois de carregar um VO.
void afterUpdate(PersistenceEvent event) throws Exception; // Executado depois de alterar o registro.
void beforeDelete(PersistenceEvent event) throws Exception; // Executado antes de remover o registro.
void beforeInsert(Persistencefvent event) throws Exception; // Executado antes de incluir o registro.
void beforeUpdate(PersistenceEvent event) throws Exception; // Executado antes de alterar o registro.
}
Para adicionar um listener em uma entidade do sistema, é necessário criar um mapeamento no arquivo correspondente à entidade, no dicionário de dados. A classe listener deve extender a classe abstrata PersistenceEventAdapter, que por sua vez implementa a interface PersistenceEventListener. A imagem abaixo representa o funcionamento do listener associado à entidade Beneficio.
1 - Entidade que está sendo "ouvida" pelo listener.
2 - BeneficioListener.java
public class BeneficioListener extends PersistenceEventAdapter{
private static final long serialVersionUID = 1l;
@Override
public void beforeInsert(PersistenceEvent event) throws Exception {
validaBeneficio((DynamicVO) event.getVo());
}
@Override
public void beforeUpdate(PersistenceEvent event) throws Exception {
validaBeneficio((DynamicVO) event.getVo());
}
private void validaBeneficio(DynamicVO benVO) throws Exception {
if (benVO.asInt("CODEVENTO") == benVO.asInt("CODEVENTOEMP")) {
throw (Exception) SKError.registry(TSLevel.ERROR, "BEN_E00001", new Exception("O cdigo do evento do beneficirio no pode ser igual ao cdigo evento da empresa."));
}
}
}
3 - Beneficio.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE entity>
<entity name="Beneficio" main-object="Beneficio" commit-type="D">
<runtime max-results="50000" timeout="20" load-on-find="true" />
<event-listener class="br.com.sankhya.beneficio.model.entitylisteners.BeneficioListener" />
</entity>
4 - Eventos de inclusão e atualização de registros na tabela disparam a execução do listener.
Para mais informações sobre como implementar listeners em extensões, acesse o artigo Recursos em extensões.
## Como tirar dúvidas?
Para tirar dúvidas e compartilhar informações, use a sala Jape da comunidade Sankhya Developer.
Updated about 1 year ago