Vou fazer um teste pra uma vaga de programador java pra JSF, ajuda. (+jpa)

Entao pessoal, finalmente apareceu uma boa oportunidade e eu quero muito essa vaga…
Ontem eu fiz uma prova escrita e consegui passar… e hoje é o dia da prova pratica…

Que vai consistir na criação de um CRUD utilizando JSF 1.2 e algum outro framework à nossa escolha… escolhi utilizar o JPA. OK
Mas ele disse tambem que a utilização de design patterns e boas práticas seriam bem avaliados… entao eu criei um projeto aqui e queria saber da opiniao de vcs.

Organização do Projeto:

queria que vocês avaliassem o meu SINGLETON:

[code]package br.com.ceuma.persistence;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class EntityManagerFactorySingleton {

private static final EntityManagerFactorySingleton singleton = new EntityManagerFactorySingleton();
private static EntityManagerFactory fabrica = null;
private final String unidadeDePesistencia;

private EntityManagerFactorySingleton() {
	this.unidadeDePesistencia = new Configuracoes().getConfigution("unidade_de_persistencia");
	System.out.println("Criando Entity");
}

public static EntityManagerFactorySingleton getInstance(){
	
	return singleton;
}

public EntityManager getManager(){
	
	try {
		if(fabrica == null){
			fabrica = Persistence.createEntityManagerFactory(this.unidadeDePesistencia);
			return fabrica.createEntityManager();
		} else {
			return fabrica.createEntityManager();
		}
	} catch (Exception e) {
		System.err.println("ERRO: " + e.getMessage());
		return null;
	}
	
}

}
[/code]

essa classe é responsavel por criar EntityManagers… ela utiliza uma outra classe utilitaria… para ler um arquivo properties… para preencher o metodo
Persistence.createEntityManagerFactory();

Eu creio que isso seja uma boa prática, particularmente nao acho interessante colocar esse tipo de informação no codigo diretamente.

[code]package br.com.ceuma.persistence;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class Configuracoes {

private InputStream stream;

public Configuracoes() {
	stream = this.getClass().getResourceAsStream("config.properties");  
}

public String getConfigution(String configucao){
	
	Properties props = new Properties();
	
	try {
		props.load(stream);
		return props.getProperty(configucao);
	} catch (IOException e) {
		System.err.println("ERRO NA LEITURA DO ARQUIVO DE CONFIGURAÇÃO) " + e.getMessage());
		return null;
	}
	
}

}
[/code]

e agora o meu DAO

[code]package br.com.ceuma.dao;

public interface DAO {
void save(T t);
void remove(T t);
T find(Long id);
void update(T t);
}
[/code]

meu BackingBean ja mapeado

[code]package br.com.ceuma.model;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name=“tb_contato”)
public class Contato {

@Id @GeneratedValue
private Long id;
private String nome;
@Column(unique=true)
private String email;
private String endereco;
@Column(name="data_nascimento")
private Date dataNascimento;

// getters & setters

[/code]

a classe que implementa o DAO

[code]package br.com.ceuma.dao;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceException;

import br.com.ceuma.model.Contato;
import br.com.ceuma.persistence.EntityManagerFactorySingleton;

public class ContatoDAO implements DAO {

private EntityManager manager;

public ContatoDAO() {
	this.manager = EntityManagerFactorySingleton.getInstance().getManager();
}

public void save(Contato t) {
	
	EntityTransaction transacao = this.manager.getTransaction();
	transacao.begin();
	
	try {
		this.manager.persist(t);
		transacao.commit();
	} catch (Exception e) {
		System.err.println("ERRO AO SALVAR O OBJETO: " + t + "\n" + e.getMessage());
		transacao.rollback();
	} finally {
		this.manager.close();
	}
}

public void remove(Contato t) {
	EntityTransaction transacao = this.manager.getTransaction();
	transacao.begin();
	
	try {
		this.manager.remove(t);
		transacao.commit();
	} catch (Exception e) {
		System.err.println("ERRO AO REMOVER O OBJETO: " + t + "\n" + e.getMessage());
		transacao.rollback();
	} finally {
		this.manager.close();
	}
}

public Contato find(Long id) {
	EntityTransaction transacao = this.manager.getTransaction();
	transacao.begin();
	
	try {
		Contato contato = this.manager.find(Contato.class,id);
		transacao.commit();
		return contato;
	} catch (NoResultException e) {
		System.err.println("Sem resultados para a consulta: " + e.getMessage() );
		transacao.rollback();
		return null;
	} finally {
		this.manager.close();
	}
}

public void update(Contato t) {
	
	EntityTransaction transacao = this.manager.getTransaction();
	transacao.begin();
	
	try {
		this.manager.merge(t);
		transacao.commit();
	} catch (PersistenceException e) {
		System.err.println("Erro ao atualizar o objeto: " + e.getMessage() );
		transacao.rollback();
	} finally {
		this.manager.close();
	}
	
}

}
[/code]

organização das classes e outros arquivos:

e agora a parte WEB… eu escolhi utilizar o facelets tbm… pq acho que ele é importante pra organização do trabalho… acho bem ‘elegante.’
segue o meu template:

[code]

Teste do UNICEUMA
	<!-- FRAGMENTO DO TOPO -->
	
	<div id="topo">
		<ui:insert name="topo">
			<ui:include src="/fragmentos/topo.xhtml" />
		</ui:insert>
	</div>
	
	<!-- FRAGMENTO DO MENU -->
	
	<div id="menu">
		<ui:insert name="menu">
			<ui:include src="/fragmentos/menu.xhtml" />
		</ui:insert>
	</div>
	
	<!-- COTEUDO PRINCIPAL -->
	
	<div id="principal">
		<ui:insert name="principal">
		</ui:insert>
	</div>
	
	<!-- FRAGMENTO DO RODAPE -->
	
	<div id="rodape">
		<ui:insert name="rodape">
			<ui:include src="/fragmentos/rodape.xhtml" />
		</ui:insert>
	</div>
	
</div>
[/code]

entao… queria saber o que vocês acharam… o que vcs acham que eu poderia fazer pra melhorar…
como estao minhas ‘boas praticas’… e se vcs puderem me ajudar a deixar esse projeto ai o mais OO possivel, seria magnifico tbm.

desde ja agradeco MESMO…

edit: pessoal, irei comentar todo o codigo ainda…

Cara, acho que o seu código está bom, bem próximo das práticas que vemos por aí. Agora, eu acho que você não deve ficar comentando o seu código não. Código bom é aquele que se explica por si. Comentar demais acaba poluindo o código e dificulta a leitura.

faeldix , primeiramente boa sorte no teste.

Só por efeito de curiosidade e também poderá ser útil pra mim futuramente, quais são os requisitos dessa vaga?

Obrigado.

meu comentário não tem nada a ver com seu código, acho que ficou muito bom

achei esse método getConfigution, só um erro bobo de gramática…rs

Eu adoro System.out.println, mas é feio, o correto seria usar log

E meu Java tá meio ultrapassado mas acho q também tá errado o DAO dar commit e rollback. Em aplicações você vai ter logicas de negócio que envolvem mais de uma operação salvar, deletar, etc, e a unidade de transação tem que englobar todas essas operações juntas. O begin, commit, rollback tem que estar em volta da lógica de negócio como um todo

[quote=victorcosta]Eu adoro System.out.println, mas é feio, o correto seria usar log

E meu Java tá meio ultrapassado mas acho q também tá errado o DAO dar commit e rollback. Em aplicações você vai ter logicas de negócio que envolvem mais de uma operação salvar, deletar, etc, e a unidade de transação tem que englobar todas essas operações juntas. O begin, commit, rollback tem que estar em volta da lógica de negócio como um todo[/quote]

faz super sentido o que vc falou… como vc faria entao?
vou pensar numa forma aqui pra vc avaliar!

[quote=faeldix][quote=victorcosta]Eu adoro System.out.println, mas é feio, o correto seria usar log

E meu Java tá meio ultrapassado mas acho q também tá errado o DAO dar commit e rollback. Em aplicações você vai ter logicas de negócio que envolvem mais de uma operação salvar, deletar, etc, e a unidade de transação tem que englobar todas essas operações juntas. O begin, commit, rollback tem que estar em volta da lógica de negócio como um todo[/quote]

faz super sentido o que vc falou… como vc faria entao?
vou pensar numa forma aqui e digo… [/quote]

Me vêm 3 opções à cabeça:

1 - abrir e fechar transações manualmente em cada método de negócio;
2 - utilizar um padrão como Open Session In View ou Open Session In Phase Listener
3 - utllizar um interceptador para métodos de negócio que abra e feche as transações

Com certeza, a opinião 3 é a mais limpa, mas é difícil de implementar se você não conta com EJB’s ou DI conteiner. A opção 1 é a mais suja, pois mistura controle de transações com regras de negócio, mas é muito mais simples para se implementar e não tem erro! A opção 2 é um meio termo, mas eu não gosto muito desses padrões não.

[quote=rmendes08][quote=faeldix][quote=victorcosta]Eu adoro System.out.println, mas é feio, o correto seria usar log

E meu Java tá meio ultrapassado mas acho q também tá errado o DAO dar commit e rollback. Em aplicações você vai ter logicas de negócio que envolvem mais de uma operação salvar, deletar, etc, e a unidade de transação tem que englobar todas essas operações juntas. O begin, commit, rollback tem que estar em volta da lógica de negócio como um todo[/quote]

faz super sentido o que vc falou… como vc faria entao?
vou pensar numa forma aqui e digo… [/quote]

Me vêm 3 opções à cabeça:

1 - abrir e fechar transações manualmente em cada método de negócio;
2 - utilizar um padrão como Open Session In View ou Open Session In Phase Listener
3 - utllizar um interceptador para métodos de negócio que abra e feche as transações

Com certeza, a opinião 3 é a mais limpa, mas é difícil de implementar se você não conta com EJB’s ou DI conteiner. A opção 1 é a mais suja, pois mistura controle de transações com regras de negócio, mas é muito mais simples para se implementar e não tem erro! A opção 2 é um meio termo, mas eu não gosto muito desses padrões não.

[/quote]

pois é… a primeira que me veio a cabeca foi criar um getTransacao e utilizar ele no ContatoBean… mas ai eu ia ter que jogar excessoes pra pilha de baixo… e ter que tratar erros no bean… ia ficar pessimo… alguma outra ideia?

Uma coisa rápida.
Isso:

if(fabrica == null){
    fabrica = Persistence.createEntityManagerFactory(this.unidadeDePesistencia);  
    return fabrica.createEntityManager();  
} else {  
    return fabrica.createEntityManager();  
}  

Tá repetindo o return desnecessariamente.

if(fabrica == null)
    fabrica = Persistence.createEntityManagerFactory(this.unidadeDePesistencia);  
return fabrica.createEntityManager();

[quote=fasts]Uma coisa rápida.
Isso:

if(fabrica == null){
    fabrica = Persistence.createEntityManagerFactory(this.unidadeDePesistencia);  
    return fabrica.createEntityManager();  
} else {  
    return fabrica.createEntityManager();  
}  

Tá repetindo o return desnecessariamente.

if(fabrica == null) fabrica = Persistence.createEntityManagerFactory(this.unidadeDePesistencia); return fabrica.createEntityManager(); [/quote]

boa… obrigado cara…

pessoal… o que vcs acham?

[code]package br.com.ceuma.dao;

import javax.persistence.EntityTransaction;

public interface DAO {
void save(T t);
void remove(T t);
T find(Long id);
void update(T t);
public void finalizar();
public void finalizar(Exception e);
}
[/code]

[code]package br.com.ceuma.dao;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import br.com.ceuma.model.Contato;
import br.com.ceuma.persistence.EntityManagerFactorySingleton;

public class ContatoDAO implements DAO {

private EntityManager manager;
private EntityTransaction transacao;

public ContatoDAO() {
	this.manager = EntityManagerFactorySingleton.getInstance().getManager();
	manager.getTransaction().begin();
}

public void finalizar(){
	this.transacao.commit();
}

public void finalizar(Exception e){
	this.transacao.rollback();
}

public void save(Contato t) {
		this.manager.persist(t);
}

public void remove(Contato t) {
		this.manager.remove(t);
}

public Contato find(Long id) {
		Contato contato = this.manager.find(Contato.class,id);
		return contato;
}

public void update(Contato t) {
		this.manager.merge(t);
}

}[/code]

[code]package br.com.ceuma.bean;

import javax.faces.event.ActionEvent;

import br.com.ceuma.dao.DAO;
import br.com.ceuma.model.Contato;
import br.com.ceuma.dao.ContatoDAO;

public class ContatoBean {

private DAO<Contato> myDAO;
private Contato contato;

public ContatoBean() {
	DAO<Contato> dao = new ContatoDAO();
	this.myDAO = dao;

	this.contato = new Contato();
}

public Contato getContato() {
	return contato;
}

public void setContato(Contato contato) {
	this.contato = contato;
}

public void salvar(ActionEvent ev){
	
	try {
		this.myDAO.save(getContato());
		this.myDAO.finalizar();
	} catch (Exception e) {
		this.myDAO.finalizar(e);
	} finally {
		this.myDAO = new ContatoDAO();
	}
}

}
[/code]

so uma duvida… durante o ciclo de vida do JSF o Bean (mapeado) é destruido ao fim das requições?
pq se nao… eu tiraria esse finally…

Se você usar a opção 1 do rmendes08, pode fazer assim para não repetir o código de abrir e fechar transação, e ainda estaria usando parte do Command Pattern, já que o avaliador disse que patterns eram bem vindos :smiley:

[code]package guj;

@SuppressWarnings(“serial”)
public class ServiceException extends RuntimeException {

public ServiceException(Exception e) {
	super(e);
}

}[/code]

[code]package guj;

import java.util.concurrent.Callable;

public class Service {

protected <T> T transaction(Callable<T> command) {
	System.out.println("Inicia Transação");
	try {
		T result = command.call();
		System.out.println("Commita Transação");
		return result;
	} catch (Exception e) {
		System.out.println("Rollbacka Transação");
		throw e instanceof ServiceException ? (ServiceException) e : new ServiceException(e);
	}
}

protected void transaction(Runnable command) {
	System.out.println("Inicia Transação");
	try {
		command.run();
		System.out.println("Commita Transação");
	} catch (Exception e) {
		System.out.println("Rollbacka Transação");
		throw e instanceof ServiceException ? (ServiceException) e : new ServiceException(e);
	}
}

}[/code]

[code]package guj;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

public class PessoaService extends Service {

public List<Object> listar() {
	return transaction(new Callable<List<Object>>() {
		public List<Object> call() {
			System.out.println("- Listar Pessoas");
			return new ArrayList<Object>();
		}
	});
}

public void salvar(final Object pessoa) {
	transaction(new Runnable() {
		public void run() {
			System.out.println("- Salvar " + pessoa);
		}
	});
}

public static void main(String[] args) throws Exception {
	PessoaService service = new PessoaService();
	service.listar();
	service.salvar("Victor");
}

}[/code]

Você pode criar suas interfaces de Command ao invés de reusar Runnable e Callable pra manter o mesmo padrão de nome do método implementado. E mudar as exceções pra Checked se quiser. Exceções da lógica de negócio vão extender de ServiceException

Aprender algum framework pra não ter que fazer isso tudo é uma opção também, se tiver tempo :stuck_out_tongue:

[quote=victorcosta]
Você pode criar suas interfaces de Command ao invés de reusar Runnable e Callable pra manter o mesmo padrão de nome do método implementado. E mudar as exceções pra Checked se quiser. Exceções da lógica de negócio vão extender de ServiceException

Aprender algum framework pra não ter que fazer isso tudo é uma opção também, se tiver tempo :P[/quote]

achei um pouco complicado… quero o mais simples possivel…
pq até pra explicar seria complicad… mas obrigado victor…

vou guardar esse codigo… pq pareceu bem funcional

Pessoal… queria agradecer a ajuda de todos… mas infelizmente acho que dessa vez nao vai dar…

A provinha era fazer um sistema com jsf 1.2 + alguns outros frameworks a nossa escolha…
escolhi trabalhar com o JPA pra acelerar o processo… a prova era pra ser feita em 3hrs… mas nao consegui concluir nesse tempo

Era um sisteminha de vendas com cadastro de clientes, vendedor, produtos e tinhamos que criar uma forma de fazer vendas e decrementar os produtos
no banco de dados… infelizmente eu fui inventar :frowning: ai como tive que desfazer algumas coisas isso levou muito tempo… infelizmente foi assim…

Mas nao recebi a resposta ainda… talvez ainda dê… mas nao tenho mais esperancas…
Mas serviu pra mostrar que eu preciso muitoooooooooo ainda trabalhar essa parte de Orientação a Objetos… ela foi quem realmente quebrou minhas pernas :frowning:

Mas enfim… obrigado a todos…
Obrigado mesmo…

Calma, podem gostar da parte que você fez mesmo que não tenha concluído, e chamá-lo para a empresa. Você podia fazer algum tipo consulta na net ou outro material? T+

nao podia… ate os templates de xmls eu tinha que fazer… (perdi muito tempo nisso)