Aprenda Java EE 6, agora! (2)

fevereiro 24th, 2009 § 2

Dessa vez, estarei utilizando a versão b37 do Glassfish v3. Por causa disso, você vai ter que fazer alterações à mão no plugin do Eclipse para o servidor Glassfish. Na versão b36 havia as pastas web e ejb dentro de module. Agora, todos os jars estão dentro de module, sem distinção de pastas.

Primeiro, feche o Eclipse. Iremos copiar o plugin do Glassfish e descompactá-lo, para alterar o seu arquivo de configurações. No Linux eu fiz assim, supondo que ECLIPSE_HOME seja uma variável onde aponta para a pasta do Eclipse: » Read the rest of this entry «

Aprenda Java EE 6, agora!

fevereiro 15th, 2009 § 4

Quando fiquei craque no Java, a versão do “Enterprise Edition” era ainda 1.4. Eu aprendi a versão 5, logo depois do lançamento do Glassfish. Mas agora estou fazendo algo diferente, não vou esperar a versão Java EE 6 sair, vou aprender as coisas tão logo as novidades apareçam.

E você também pode fazer isso. Pegue uma versão promoted do Glassfish no site deles, que, assim como o Lost, tem sempre uma versão nova nas quartas à noite, que você baixa na quinta. A última versão, que estou usando nesta semana, é a b36.

Baixe a última versão disponível e descompacte num lugar que você achar apropriado. No Eclipse, na hora de instalar o servidor, basta escolher a opção “Glassfish v3 Prelude” (se você não usava Glassfish, na tela de novo servidor há uma opção de baixar os adaptadores para outros servidores). Pronto!

Eu vou fazer uma aplicação de exemplo, que é uma agenda de consultório médico. É babaca, mas tem uma regras óbvias que não dá pra ser tratado com o velho CRUD.

Vamos lá. Crie um “Dynamic Web Project” cujo Runtime seja o “Glassfish v3 Prelude”, vou chamá-lo de AgendaMedica. Não sei como vocês lidam com testes no Eclipse, mas costumo criar um novo projeto Java que referencia o projeto que estou interessado em testar. No caso, criarei também o projeto Java AgendaMedicaTeste. Após criado, dê <Alt> + <Enter> sobre o projeto, clique em “Java Build Path”, vá na aba “Projects” e adicione o projeto AgendaMedica.

No projeto AgendaMedicaTeste, eu já criei um método de testes pra realizar a consulta:

package br.com.objectzilla.agendamedica;
 
import java.util.Calendar;
 
import org.junit.Assert;
import org.junit.Test;
 
public class AgendamentoTeste {
 
	@Test
	public void pacienteMarcaHoraComMedico() {
		// um paciente...
		Paciente paciente = new Paciente();
		paciente.setNome("Maria");
 
		// um médico...
		Medico medico = new Medico();
		medico.setNome("Dr. Gregory House");
 
		// ambos agendam um horário
		Agendamento agendamento = new AgendamentoImpl();
		Calendar horario = Calendar.getInstance();
		horario.set(2009, Calendar.MARCH, 5, 17, 00, 00);
 
		agendamento.marcaConsulta(medico, paciente, horario);
 
		// agora, médico tem consulta com paciente marcada às 5
		Paciente pacienteMarcado = medico.consulta(horario);
		Assert.assertEquals(paciente.getNome(), pacienteMarcado.getNome());
	}
}

Beleza, mas o código não compila, né? Ora, não seja por isso. Vá criando as classes clicando nos erros com o botão direito do mouse, só não se esqueça de colocar as classes no projeto AgendaMedica. No caso, Agendamento é uma interface e o restante são classes.

Bom, tente rodar o script de teste (clique com botão direito sobre a classe e dê Run As… > JUnit Test). Vai dar erro, óbvio! Por isso, convido a você a escrever código nas classes até o script rodar com sucesso. Não se preocupe, se você não conseguir ou não tiver paciência, no final do post eu mostro o link onde você pode baixar o código.

Agora, vamos transformar a interface Agendamento em um Stateless Session Bean. Não precisa nem mover pra um projeto próprio, pois agora os EJBs podem ser “deployados” em aplicações WAR. Basta adicionar @Local na interface (a v3 ainda não possui suporte a @Remote), assim:

@Local
public interface Agendamento {
	// ...
}

E adicionar @Stateless na classe que implementa:

@Stateless
public class AgendamentoImpl implements Agendamento {
	// ...
}

Pronto, faça o deploy do projeto web no servidor Glassfish v3 e veja o seguinte log aparecer:

INFO: Bound Java:Global name [business view] : java:global/AgendaMedica/AgendamentoImpl#br.com.objectzilla.agendamedica.Agendamento
INFO: Bound Java:Global name [single business view] : java:global/AgendaMedica/AgendamentoImpl

Repare em como é realizado o binding com o JNDI. A partir da versão 6, não será mais uma implementação específica de contêiner. Todos os servidores de aplicações, se quiserem ser homologados para Java EE 6, deverão dispor seus EJBs, em contextos JNDI, de acordo com o seguinte padrão:

java:global[/<application-name>]/<module-name>/<bean-name>#<interface-name>

Onde:

<application-name> é opcional, refere-se ao nome do pacote EAR (não tem no nosso caso).

<module-name> é o módulo onde está o EJB (AgendaMedica).

<bean-name> é o nome do bean (AgendamentoImpl).

<bean-name> é o nome do bean (AgendamentoImpl).

<interface-name> é o nome completo da interface que implementa o bean (br.com.objectzilla.agendamedica.Agendamento).

O leitor atento deve ter reparado: está sendo feito dois bindings para o EJB! Isso também faz parte do padrão. Se o bean implementar apenas uma interface, um alias será criado onde o nome da interface não aparece.

Já que criamos o Session Bean, seria interessante se usássemos, não é não? Vamos fazer um Servlet, mas não precisa tomar o susto de configurar o wer.xml, pois basta criar um classe que herde de HttpServlet e adicionar uma anotação de acordo com o seguinte código:

@WebServlet(value="/agendamento")
public class AgendamentoServlet extends HttpServlet {
 
	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
			IOException {
 
	}
}

Após o deploy, basta digitar http://localhost:8080/AgendaMedica/agendamento e você vai ver… uma tela em branco. Normal, a gente não fez nada mesmo. Agora, vamos preencher o doGet() com uma chamada ao método de marcarConsulta() de agendamento. Eu também injetei uma instância de EJB.

@WebServlet(value="/agendamento")
public class AgendamentoServlet extends HttpServlet {
 
	@EJB
	private Agendamento agendamento;
 
	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
			IOException {
 
		String nomeMedico = req.getParameter("medico");
		String nomePaciente = req.getParameter("paciente");
		int hora = Integer.parseInt(req.getParameter("hora"));
 
		// criando médico
		Medico medico = new Medico();
		medico.setNome(nomeMedico);
 
		// criando paciente
		Paciente paciente = new Paciente();
		paciente.setNome(nomePaciente);
 
		// criando horário
		Calendar horario = Calendar.getInstance();
		horario.set(Calendar.HOUR, hora);
		horario.set(Calendar.MINUTE, 0);
		horario.set(Calendar.SECOND, 0);
 
		// chamando método de agendamento
		agendamento.marcaConsulta(medico, paciente, horario);
 
		PrintWriter pw = resp.getWriter();
		pw.format("Eu juro que marquei consulta para o paciente %s, com o médico %s, na hora %d.",
				medico.getNome(), paciente.getNome(), horario.get(Calendar.HOUR));
 
 
	}
}

Se você rodar http://localhost:8080/AgendaMedica/agendamento?medico=Jose&paciente=Adolfo&hora=14, vai ver que a aplicação mostra uma mensagem na tela que não diz se foi, ou não foi, feito algo. Precisaria de uma tela de consulta, mas só dá pra fazer isso se nossa aplicação persistisse os objetos entre as requisições, o que atualmente não ocorre.

Vou fazer isso no próximo post, onde apresentarei mais novos recursos e novas funcionalidades na aplicação pra que ela finalmente funcione de verdade.

Quem quiser, pode ir alterando a aplicação por conta própria, deixei no repositório GitHub em http://github.com/leonardoverissimo/javaee-6-application/tree/master.

Filho de feio inteligente com gostosa burra

fevereiro 10th, 2009 § 0

Seguinte, na segunda-feira (09/fev), eu vi um PDF sobre uma experimentação de tipagem estática em Python. Não que eu esteja duvidando da capacidade dos caras que fizeram a apresentação, até porque, mexer com linguagens não é para qualquer um, mas sei lá, o fato de muita gente ter dado um “up” no Reddit implica que muita gente sonha com uma linguagem cuja tipagem é tanto estática quanto dinâmica.

Isso me preocupa, sabia? A impressão que dá é que as pessoas sonham com uma espécie de uma linguagem meio-termo, que acabasse com as guerras nerdísticas e que fosse a única que reinaria soberana sobre todos as outras. E uma que fosse estática e dinâmica, ao mesmo tempo, seria a candidata ideal. Infelizmente, tenho que te contar a triste realidade: tipagem estática e dinâmica são antagônicas, tipo água e vinho.

Você já programou em C++? Então, quem conhece o troço sabe que existem vários paradigmas conflitantes entre si. Um paradigma é a programação procedural com conteineres STL, outro é a programação orientada a objetos e outro é programação por templates. Todos bem diferentes, e cuja mistureba só pode ser feita com bastante cuidado por gente que não tem amor à própria vida. Sim, é realmente complicado programar em templates e depois tentar usar OO, é complicado usar o paradigma C quando boa parte do código já está com a sintaxe do C++. E eu desconfio que a mesma coisa pode ocorrer com essas linguagens que misturam tipagem estática e tipagem dinâmica. Vamos fazem uma experimentação com Groovy? Primeiro: o que acontece quando compilamos (com groovyc) o seguinte trecho?

// recebe um objeto de tipo indefinido
def imprima(valor) {
    println valor
}
 
// objeto de tipo "String" numa referência de tipo "String"
String msg = "Olá"
 
// objeto de tipo "String" passado para parâmetro sem tipo
imprima msg

Sucesso, é perfeitamente possível passar um objeto qualquer numa referência sem tipo.

Mas, e se invertermos, assim?

// recebe um objeto de tipo "String"
def imprima(String valor) {
    println valor
}
 
// objeto de tipo "String" numa referência sem tipo
msg = "Olá"
 
// objeto de tipo "String" passado para parâmetro de tipo "String"
imprima msg

Sucesso também, o compilador não reclama quando uma referência String recebe um objeto de uma referência sem tipo. E se chutarmos o balde, definindo a função imprime() recebendo um int?

// recebe um objeto de tipo "int"
def imprima(int valor) {
    println valor
}
 
// objeto de tipo "String" numa referência de tipo "String"
String msg = "Olá"
 
// objeto de tipo "int" passado para parâmetro de tipo "String"
imprima msg

Acha que dá erro de compilação? Dá nada! Compila com sucesso também! Não existem casos específicos para isso. Em Groovy, os tipos não são decididos em tempos de compilação. Erros de tipos só são descobertos quando você executa o código com tipagem divergente.

Não tenho nada contra linguagens de tipagens estáticas, nem de dinâmicas. Só acho que cada um deve estar no seu quadrado. Muito se fala que, com linguagens “mistas”, como Groovy, se obtém os benefícios da tipagem estática com os benefícios da tipagem dinâmica. Será mesmo? Vamos pensar: Em minha opinião, a vantagem da tipagem estática é a possibilidade de reduzir erros causados por atribuições errôneas, impossibilitanto até mesmo e existência do código executável; a desvantagem é que os tipos estáticos causam um engessamento da aplicação (a famosa dúvida: “como trocar a classe, uma vez que as referências são da classe antiga?”), e cuja solução (criação de classes abstratas e de interfaces) precisa ser feita no começo do desenvolvimento.

A vantagem da tipagem dinâmica (de novo, em minha opinião) é possibilitar um código mais flexível pois, como as referências não se comprometem com tipos, uma nova classe com os mesmos contratos de uma antiga sempre será substituível por esta. A desvantagem é que, principalmente com APIs públicas ou com equipes dispersas, torna-se mais difícil definir um contrato dos métodos e classes.

Veja, Groovy não tem aquela vantagem de uma linguagem estática. Se você retornar, em uma função, um valor de tipo diferente, é possível quebrar o código em algum outro lugar e você nem perceber. Significa que precisará de uma grande suíte (e de uma forte cultura) de testes unitários, como qualquer linguagem dinâmica.

E também não tem aquela vantagem de uma linguagem dinâmica. Tipos não são garantias de que métodos obedeçam estritamente um contrato. Em linguagens “puramente” dinâmicas, como não há tipos nas referências, é permitido uma certa flexibilidade do que se pode ou não pode aceitar. Exemplo, em Ruby, poderia ter métodos que recebem valores válidos, não importando seu tipo.

# classe hipotética Triângulo
# válido
t = Triangulo.new :tipo=>:retangulo
 
# válido também, por que não?
t = Triangulo.new "tipo"=>"retangulo"
 
# válido
t.hipotenusa 10
 
# válido, por que não?
t.hipotenusa "10"
 
# opa! erro! O método lança exceção!
t.cateto_oposto -4

Tá vendo, os métodos podem tanto receber String quanto números, o importante é o valor resultante ser um número natural. O pensamento da tipagem limita essas espertezas, pois fica-se o tempo todo imaginando: “Não! Esse método tem que receber uma ‘classe X’!” (Pior que o indivíduo se esquece até da diferença entre objeto e classe.). Como Groovy não vai incentivar ninguém a abandonar os tipos em tudo quanto é canto, também não se receberá os benefícios das linguagens dinâmicas.

Então, pra amarrar com o título acima. Sou da opinião de que Groovy é ruim… não, corrigindo… de que Groovy é a pior linguagem do mundo porque, ao unir o feio inteligente (a tipagem estática) com a gostosa burra (a tipagem dinâmica), não se deu origem a um filho bonito e inteligente, como era de se esperar.

Foi pior, o filho é feio e burro.

Where am I?

You are currently viewing the archives for fevereiro, 2009 at Objectzilla.