[ Resolvido ] Duvida - Como tratar exeções? usando o demoiselle

11 respostas
R

Olá Pessoal, eu ja desenvolvo pra essa ferramenta a algum tempo porem sem os testes de erros… forcar um erro para que ocorra a exeção.

ai esses dias recebi uma tarefa para resolver isto, e me veio a pergunta:

  • Se o demoiselle ja te “maravilha”, a gente esquece do básico, então pergunto a vós, onde que fica as classes de persistencia e de cruds para que a exeção seja tratada?

ja rodei, procurei, e não consigo achar essa bendita cuja…

alguem ajuda ai?

11 Respostas

L

Não entendi sua dúvida. Pode ser mais específico?

R

tipo… no Demoiselle, ele ja te faz toda a parte de persistência, negócio pra voce… voce não se dá o trabalho de criar cruds… certo?

agora por exemplo: na minha classe java eu tenho lá User.java

@Id
private Long id;

private String nome;

@colunm(unique=true")
private String cpf;

digamos que ja tenhamos TODA a parte de web ja pronta. agora rodamos a aplicação e inserimos o primeiro cadastro. certo?ok. cadastrou.

agora vamos cadastrar o segundo, mais eu coloco o mesmo CPF de propósito, vai dar pau certo? ok. como eu vou tratar essa exeção? ja que as classes de persistência são do JPACrud dele…

eu achei isso:

Demoiselle E@D: Módulo 3 - Aula 1 - Tratanto exeções.

porem eu fico me perguntando toda vez que vou tentar implementar: “onde diabos eu vou colocar isso ?”


ta mais específico? xD

L

Bom, o ideal seria que antes de inserir o registro você verificasse se o cpf informado já existe. Caso exista você envia msg para o usuário, pode ser via uma exception de validaçãotipo ValidationException ou BusinessException, ou simples adicionando a msg direto, dizendo que o cpf já está cadastrado. De qualquer forma se alguma exceção for lançada na sua camada de DAO, é uma exceção que provalvemente você não tem com se recuperar, do tipo violação de contraint, o banco caiu, servidor ta fora, erro de syntax SQL, enfim. Como as mensagens de validação você vai ta enviando via uma exceção especifica como as que eu citei do tipo Validation ou BusinessException ou qualquer uma que queira, então na sua camada web você tem como sabe como tratar cada tipo de exceção. Vindo uma de validação vc exibe a propria msg da exception (‘CPF JÁ CADASTRADO’), vindo qualquer outra exception que nao seja de validação de regra de negocio ou qualquer outra validação em si, você exibe uma msg padrão do tipo ‘NÃO FOI POSSÍVEL EFETUAR ESSA OPERAÇÃO’, e loga (usando um logger tipo log4j), a real causa do erro.

Então, vamos lá. Sua dúvida é onde colocar o método ExcpetionHandler. Você pode ter várias abordagens, uma delas é na sua camada web, que é a camada que vai acessar todo o serviço provido pela sua camada de negócio, voc~e pode ter seus ExceptionHandlers la. De modo que podiamos ter dois métodos cada um tratando um tipo de exception diferente, como abaixo:

Tratar BusinessException

@ExceptionHandler
public void tratarBusinessException(BusinessException ex){
//enviar msg da falha de validação para a visão do usuário
}

Tratar Qualquer outra exception resutante de algum problema que a aplicação não pôde se recuperar

@ExceptionHandler
public void tratar(RuntimeException ex){
//enviar msg de erro padrão e logar o erro via logger.
}

Lembro que mesmo o fato de seus DAOs estenderem de JPACrud não implica em nada e não quer dizer nada isso. Se ocorrer algum problema a exceção será levantada e você deve usar o handler onde você deseja trata-la seja no seu BusinessController, seja no seu managedBean (se estiver usando JSF), seja no seu action (se estiver usando struts), etc…

Espero ter ajudado.

R

lindberg713 ajudou sim!

agora vou ler… reler o que vc colocou ai, e ver se consigo fazer essa implementação.

vou deixar o topico ainda blz? \o caso preciso de ajuda… obrigado mesmo!

L

Tranquilo cara. Tenta entender e fazer. Caso não entenda ou encontre algum problema ou dúvida posta ai que agente tira. Pense que os DAOS da sua aplicação compoem sua camada de persistencia, então você até poderia ter o ExceptionHandler la, mas creio que não é responsabilidade do DAO tratar isso de uma forma geral, salvo nos casos de exceptions especificas de persistencia e nas que são desta camada e relacionadas a sua lógica. Então pense que o DAO vai lançar a exception para as camadas acima, BusinessController (Service, etc…), Fachada, Controladores de Visão (managedbeans e actions), então essas camadas acima receberão essa exception, então cabe a você definir qual será a abordagem e onde ficará esse tratamento das exceptions da sua aplicação com validações de cpf, regra de negocios em si e das outras exceptions, como as de banco. Uma boa, creio que seria colocar esses exceptionhandlers no seu controlador de visão, managedbean (jsf) ou action(struts) e la é decidido como cada exception será tratada. Isso deixa livre para a camada superior (visão) que vai consumir os serviços da sua camada de negocio decidir o que fazer. Dessa forma, se você tiver por exemplo um outro subsistema (módulo) acessando sua camada de negocio, ele esteja livre para decidir como tratar a exception lançada pela sua camada de negocio.

Espero ter ajudado ainda mais.

Qualquer coisa posta ai.

R

lindberg713, me tira outra duvida.

Estou querendo fazer a implementação de Spring Security certo? fiz em um projeto modelo(com bd local), funcionou tranquilo, fiquei até feliz.

Porem quando eu faço essa comunicação por WS como faz?

pq no arquivo do AplicationContext.xml ele tem os arquivos de configuração… etc… porem tem um trecho lá que ele faz um SQL com o bd local. como seria isso pra um ws?

R

lindberg713, tentei implementar lá o tratamento de erro seguindo a video aula, porem sem sucesso.

Segue o meu View: ClienteEditMB.java

package br.unipe.akropolis.view;

import java.util.ArrayList;
import java.util.List;

import javax.faces.model.SelectItem;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.FlushModeType;
import javax.persistence.Query;

import org.hsqldb.persist.Logger;

import br.gov.frameworkdemoiselle.annotation.PreviousView;
import br.gov.frameworkdemoiselle.exception.ExceptionHandler;
import br.gov.frameworkdemoiselle.stereotype.Controller;
import br.gov.frameworkdemoiselle.stereotype.ViewController;
import br.gov.frameworkdemoiselle.template.AbstractEditPageBean;
import br.gov.frameworkdemoiselle.transaction.Transactional;
import br.unipe.akropolis.business.ClienteBC;
import br.unipe.akropolis.business.GrupoBC;
import br.unipe.akropolis.business.PromotoresBC;
import br.unipe.akropolis.domain.Cliente;
import br.unipe.akropolis.domain.Grupo;
import br.unipe.akropolis.domain.Pessoa;
import br.unipe.akropolis.domain.Promotores;
import br.unipe.akropolis.domain.TipoQuarto;
import br.unipe.akropolis.domain.Usuario;

@Controller
@ViewController
@PreviousView("/cliente_list.xhtml")
public class ClienteEditMB extends AbstractEditPageBean<Cliente, Long> {

	private static final long serialVersionUID = 1L;

	@Inject
	private ClienteBC clienteBC;
	@Inject
	private PromotoresBC promotoresBC;
	
	@Override
	@Transactional
	public String delete() {
		this.clienteBC.delete(getId());
		return getPreviousView();
	}

	@Override
	@Transactional
	public String insert() {
		this.clienteBC.insert(getBean());
		return getPreviousView();
	}

	@Override
	@Transactional
	public String update() {
		this.clienteBC.update(getBean());		
		return getPreviousView();
	}

	@Override
	protected void handleLoad() {
		setBean(this.clienteBC.load(getId()));
	}
		
	public List<SelectItem> getListaPromotores() {
		List<Promotores> listaPromotores = this.promotoresBC.findAll();
		List<SelectItem> items = new ArrayList<SelectItem>();
		for (Promotores p: listaPromotores){
			items.add(new SelectItem(p, p.getPessoaFisica().getPessoa().getNome()));
		}
		return items;
	}
	
	@ExceptionHandler
	public void tratarDataException(Exception e){
		System.out.println("Erro: "+e.getMessage());
	}
}

Como voce falou, geralmente isto é colocado na classe de visão. então eu o fiz.

porem não pegou.. =[

Classe Model:
Cliente.java

package br.unipe.akropolis.domain;

import javax.persistence.*;

@Entity
public class Cliente {
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "idcliente")
	private Long id;
	
	@OneToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
	private PessoaFisica pessoaFisica;
	@Column(unique=true)
	private String passaporte;
	
	@OneToOne(fetch=FetchType.LAZY)
	private Promotores promotores;
	
	@OneToOne(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
	private Endereco endereco;
	

	public Cliente() {
		this.id = new Long(0);
		this.pessoaFisica = new PessoaFisica();
		this.passaporte = new String();
		this.endereco = new Endereco();
	}

	public Cliente(PessoaFisica pessoaFisica, Promotores promotores, String passaporte, Endereco endereco) {
		this.pessoaFisica = pessoaFisica;
		this.promotores = promotores;
		this.passaporte = passaporte;
		this.endereco = endereco;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public PessoaFisica getPessoaFisica() {
		return pessoaFisica;
	}

	public void setPessoaFisica(PessoaFisica pessoaFisica) {
		this.pessoaFisica = pessoaFisica;
	}

	public String getPassaporte() {
		return passaporte;
	}

	public void setPassaporte(String passaporte) {
		this.passaporte = passaporte;
	}

	public Promotores getPromotores() {
		return promotores;
	}

	public void setPromotores(Promotores promotores) {
		this.promotores = promotores;
	}

	public Endereco getEndereco() {
		return endereco;
	}

	public void setEndereco(Endereco endereco) {
		this.endereco = endereco;
	}	

}
L

Cara, bom dia!

  • Respondendo seu primeiro post, com relação ao spring security. Para customizar o serviço de obtenção de dados do usuário a titulo de efetivação de login, de modo a você fazer usando um Web Service, um xml, acessando uma fachada de um outro subsistema, enfim… fazendo o que vc quiser da forma como quiser, você precisa implementar um UserDetailsService. Esta interface define um método chamado loadUserByUsername e que recebe um parametro “String username” e retorna um UserDetails. O spring vai chamar esse cara passando o username do cara que ta tentando logar então sua implementação do método loadUserByUsername é que vai obter e devolver o UserDetails, que é uma interface que prover os métodos de obtenção do password, username, permissoes, etc… Então o que você tem que fazer é implementar seu UserDetailsService e no método loadUserByUsername chamar o cliente do seu webService para obter as informações do usuário e dessa forma montar um UserDetails com os dados do cara. Uma vez que o spring tem o username e a senha que o cara informou na tela de login e obteve os dados reais do usuário com o username passado, então ele vai validar a autenticação. Só que você tem que declarar no seu applicationContext.xml a implementação de UserDetailsService que vai usar. Abaixo vai um exemplo:

Exemplo de como poderia ser seu UserDetailsService acessando o WS. É só um exemplo, você deve implementar a lógica correta e real.

public class MyUserDetailsService implements UserDetailsService{

	private ClienteWS clienteWS;
	
	public MyUserDetailsService() {
		clienteWS = new ClienteWS();
	}
	
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException {
		UserDetailsImpl user = clienteWS.findUser(username);
		
		if (user == null)
			throw new UsernameNotFoundException("Usuário não encontrado");
		
		return user;
	}
	
}

Implementar exemplo de UserDetails.

public class UserDetailsImpl  implements UserDetails{
	
	private static final long serialVersionUID = 1L;

	private String username;
	
	private String password;
	
	private Collection<GrantedAuthority> authorities;

	public UserDetailsImpl(String username, String password,
			Collection<GrantedAuthority> authorities) {
		this.username = username;
		this.password = password;
		this.authorities = authorities;
	}

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return authorities;
	}

	@Override
	public String getPassword() {
		return password;
	}

	@Override
	public String getUsername() {
		return username;
	}

	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean isEnabled() {
		return true;
	}
	
	@Override
	public int hashCode() {
		return getUsername().hashCode();
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof UserDetailsImpl) {
            return getUsername().equals(((UserDetailsImpl) obj).getUsername());
        }
        return false;
	}
}

Os métodos equals e hashcode são importantes para o sprign security fazer comparações entre os usuários logados, como por exemplo, quando vc define que um usuário só pode ter no máximo uma sessão ativa, então se um usuário tiver logado e este mesmo usuário vai fazer login em outro browser ou outra máquina por exemplo, o spring security usa esses métodos para verificar e comparar se o usuário ja esta logado e assim efetuar o devido tratamente.

Agora você precisa declarar no seu applicationContext.xml que vai usar sua implementação de UserDetailsService. Como abaixo:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
				   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
				   http://www.springframework.org/schema/security
          		   http://www.springframework.org/schema/security/spring-security-3.1.xsd">
	
	<!-- Aqui ficam suas demais configurações de segurança, como as urls, suas devidas autorizações, etc.. -->
	
	<bean id="myUserDetailsService" class="exemplo.MyUserDetailsService"/>
  	
  	<security:authentication-manager>
    	<security:authentication-provider user-service-ref="myUserDetailsService"/>
  	</security:authentication-manager>
  	
</beans>

Pronto, agora quando o spring vai usar a sua implementação de UserDetailsService para obter as informações de autenticação de usuários e assim efetivar/validar a autenticação dos mesmos.

  • Respondendo sua outra questão com relação ao ExceptionHandler do demoiselle, não tenho certeza mas pode ser que ele só funcione com RuntimeException. Então muda o parametro do teu metodo tratarDataException para RunTimeException e testa. Caso ainda assim não funcione, posta aqui o seu BC e me diz onde que vc ta lançando a exception para testar se o exceptionhandler ta funcionando. Pois logicamente para ele funcionar alguem tem que lançar uma exceção e jogar pra cima até a visão e nenhum try catch captura-lo. Então testa se nao fucnionar, posta ai pra agente ver o que ta acontecendo.

  • Uma outra coisa que quero te dizer é que já que vc ja anotou sua classe MB com @ViewController você não precisa anotar com @Controller pois @ViewController é um tipo de Controller e vai funcionar do mesmo jeito, é como uma especialização de controladores só que de visão. Se abrir o código de @ViewController, veja que esta annotation ja esta anotada com @Controller, então não tem necessidade de repeti-la em seu MB, vc estará sendo redundante.

Cara, vou te dizer uma coisa. Não sei por qual motivo, razão ou circunstancia você ta usando esse Demoiselle. Conheço esse framework. E posso te dizer por conhecimento de causa. Esse framework é horrível. Prover soluções mau feitas e mau projetadas de de coisas que outros frameworks de verdade e consolidados na comunidade fornecem com maestria. Use um framework de verdade, um framework solido e consolidado na comunidade. Use um framework de verdade, um framework em outras palavras que é um FRAMEWORK e não esse conjunto de classes mau escritas, mau projetadas, mau documentadas, cheio de bugs, chamado Demoiselle. Em outras palavras, USE O SPRINGFRAMEWORK.

Posso te dar todo o suporte e orientação, se tiver alguma dúvida para usar o spring no que quiser. Inclusive, para remover esse demoiselle e aplicar um verdadeiro container de inversão de controle aplicado a injeção de dependencias, como o spring, um verdadeiro gerenciador transparente (E CONFIÁVEL) de transações, spring, enfim, me diga o que quer e te digo o que usar do spring e como aplica-lo a sua arquitetura. Claro que aqui nao da pra explicar tudo. Mas te passo artigos e posts onde poderá buscar seu caminho. E o melhor de tudo, TUDO INTEGRADO, pois tudo é spring, e mesmo o que não é spring, como JSF por exemplo, ou hibernate ou jpa, integrado também com spring, que fornece integração nativa a estes frameworks de forma elegante. E mesmo onde o spring não prover, sua arquiterua flexivel, prover diversos pontos configuraveis e de estenção, que lhe permitem de forma segura e elegante prover o comportamente que deseja.

Então, é isso, springframework cara, e versão atual do framework a 3, ta bem melhor, melhor ainda. Um framework de verdade e de confiança.

É isso, espero ter ajudado.

R

vlwww lindberg! vou pesquisar mais sobre o mesmo. e gostaria sim dos seus links, e posts…

pois eu ja tinha notado que spring é de fato um otimo framework. quero estudar isso mais a fundo!

Agradeço muito sua ajuda, e ja percebi que eu vou muito te abusar com duvidas! rsrs

L

Verifiquei agora que há um bug, mais um, na versão atual do demoiselle com relação a exceções checadas que é o seu caso. Como pode ver nesse link: http://sourceforge.net/apps/mantisbt/demoiselle/view.php?id=752

Foi corrigido mas ainda nao ta em release, só snapshot, então vc se quiser de fato usar checadas, terá que usar, enquanto nao sai a release, a versão 2.2.2-SNAPSHOT do demoiselle.

Creio que usar não checadas (RuntimeException) pra o seu caso é o suficiente.

Espero ter ajudado.

L

Cara, ok então. Posso te ajudar no que precisar sim. Mas por aqui nao da pra ta discutindo coisas fora do topico. Melhor por email. Meu email é [email removido]

Mas desde já, pelo que pude sentir, to vendo que é iniciante e te digo que é importante, muito muito importante aprender a buscar, pesquisar e aprender na documentação das coisas. Tudo em java tem documentação. A documentação do spring por exemplo, é maravilhosa, é uma das melhores. Sem contar o google que te ajuda em tudo. Então se condicione a sempre quebrar a cabeça e queimar a pestana para resolver os problemas por si só, aprender as coisas por si só pois isso vai te “calejar” com o tempo, vai te trazer calos e te fazer um desenvolvedor auto-suficiente.

De qualquer forma, no meu tempo livre no que eu puder ajudar a vc e a quem precisar serei solicito.

Criado 8 de março de 2012
Ultima resposta 14 de mar. de 2012
Respostas 11
Participantes 2