Artigos com o marcador JEE

Dominando o Spring Roo, publicado na Java Magazine 79

Java Magazine 79

Sim é verdade, faz tempo que não escrevo nada para o blog. Infelizmente tenho andado bem ocupado com estudos, trabalho e família, mas hoje trago nesse post uma boa notícia. :D

Hoje a revista Java Magazine publicou a versão digital da edição 79 e muito em breve deverá publicar também a sua versão impressa.

Estou escrevendo este post no meu blog sobre esta revista e principalmente sobre esta edição, porque ela contém meu primeiro artigo para esta revista.

O artigo aborda de uma forma teórica e prática o uso do Spring Roo que é classificado como uma ferramenta para desenvolvimento ágil de aplições web utilizando a linguagem Java.

Infelizmente não vou colocar todo o conteúdo do artigo aqui :D , então por favor, leiam a revista para conferir o artigo completo e depois me mandem suas opiniões, críticas e sugestões ;) para que os próximos artigos sejam melhores.

Para ver o site da revista, clique na imagem da capa da revista e para ver a revista no formato digital, clique no link a seguir:

Clique aqui para acessar a revista online

Veja abaixo um resumo do que você vai encontrar no artigo:

Neste artigo você vai entender o que é o Spring Roo, sua arquitetura, como ele funciona para proporcionar mais agilidade no desenvolvimento, suas principais características e funcionalidades, e como utilizá-lo para desenvolver aplicativos de forma mais rápida e sem perder qualidade.

O exemplo prático desse artigo, embora simples, utilizará frameworks como Spring IOC/DI e MVC, Hibernate, Tiles e Bean Validation, envolverá também testes de integração baseados em JUnit, internacionalização, rotinas em AspectJ e controle de dependências via Maven.

Vale ressaltar que a utilização da maioria destes frameworks/ferramentas acontecerá de forma transparente para o desenvolvedor, e não se espante ao ver que o exemplo será gerado com a execução de aproximadamente 15 linhas.

Testando JavaEE 6 com Glassfish e Eclipse

Neste post, vou mostrar algumas novidades do Java EE 6.
Eu vou usar os seguintes softwares:

Glassfish v3
Eclipse Galileo JEE Edition

Depois de instalá-los, vou criar um Dynamic Web Project no Eclipse chamado de FirstProjectJEE6:

Agora vou substituir o conteúdo do arquivo web.xml por este abaixo:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	version="3.0">
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
</web-app>

Para compilar nosso projeto, precisamos adicionar um jar externo chamado javaee.jar ao projeto (Build Path), o arquivo jar pode ser encontrado em [glassfish_directory]/glassfish/lib/javaee.jar

Criei também um script ant para fazer o deploy da nossa aplicação diretamente no glassfish. Este script deve ser salvo na raiz do projeto, salvei ele com o nome de build.xml. A seguir segue seu conteúdo:

<?xml version="1.0" encoding="UTF-8"?>
<project name="FirstProject JavaEE 6" basedir="." default="deploy">
	<property name="warfile" value="FirstProject" />
	<target name="create">
		<war destfile="${warfile}.war" webxml="WebContent/WEB-INF/web.xml" update="true">
			<classes dir="build/classes" />
			<fileset dir="WebContent">
				<exclude name="WEB-INF/web.xml" />
			</fileset>
		</war>
	</target>
	<target name="copy">
		<copy todir="/Users/rodrigolazoti/Programs/glassfishv3/glassfish/domains/domain1/autodeploy" overwrite="true">
			<fileset dir=".">
				<include name="*.war" />
			</fileset>
		</copy>
	</target>
	<target name="deploy">
		<antcall target="create" />
		<antcall target="copy" />
	</target>
</project>

Note que esse local:
/Users/rodrigolazoti/Programs/glassfishv3/glassfish/domains/domain1/autodeploy
Deve ser substituído por:
[your glassfish]/glassfish/domains/domain1/autodeploy

Agora, vamos codificar um pouco, primeiro vamos criar dois EJB’s usando um pouco da nova especificação.
Vou criar um EJB Stateless e um EJB Staleful, o stateful servirá apenas para representar o número de requisições feitas e o stateless servirá para retornar alguma mensagem para o usuário.

Esse é o código do EJB Stateless:

package br.com.rodrigolazoti.firstproject.service;

import javax.ejb.Stateless;

@Stateless
public class MyStatelessSessionBean {

	public String createMessage( String username ) {
		String message = "Hello World, ";

		if ( username != null && !"".equals( username.trim() ) ) {
			message += username + "!";
		}
		else {
			message += "stranger!";
		}

		return message;
	}

}

E este é o código do EJB Stateful:

package br.com.rodrigolazoti.firstproject.service;

import javax.ejb.Stateful;

@Stateful
public class MyStatefulSessionBean {

	private int amountOfrequests = 0;

	public int getAmountOfrequests() {
		return ++amountOfrequests;
	}

}

Note que em ambos EJB’s, não foi necessário criar interfaces locais ou remotas. :)

Com nossos EJB’s prontos, vamos criar um servlet para responder ao seguintes métodos http GET e POST.

package br.com.rodrigolazoti.firstproject.controller;

import java.io.IOException;

import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import br.com.rodrigolazoti.firstproject.service.MyStatefulSessionBean;
import br.com.rodrigolazoti.firstproject.service.MyStatelessSessionBean;

@WebServlet( name = "MyServlet", urlPatterns = { "/hello" } )
public class MyServlet extends HttpServlet {

	private static final long serialVersionUID = -2206981309178199835L;

	@EJB
	private MyStatefulSessionBean myStatefulSessionBean;

	@EJB
	private MyStatelessSessionBean myStatelessSessionBean;

	@Override
	protected void doGet( HttpServletRequest request, HttpServletResponse response )
			throws ServletException, IOException {
		String message = myStatelessSessionBean.createMessage( null );
		request.setAttribute( "message", message );

		int amountOfRequests = myStatefulSessionBean.getAmountOfrequests();
		request.setAttribute( "amountOfRequests", amountOfRequests );

		request.getRequestDispatcher( "/hello.jsp" ).forward( request, response );
	}

	@Override
	protected void doPost( HttpServletRequest request, HttpServletResponse response )
			throws ServletException, IOException {
		String username = request.getParameter( "username" );
		String message = myStatelessSessionBean.createMessage( username );
		request.setAttribute( "message", message );

		int amountOfRequests = myStatefulSessionBean.getAmountOfrequests();
		request.setAttribute( "amountOfRequests", amountOfRequests );

		request.getRequestDispatcher( "/hello.jsp" ).forward( request, response );
	}

}

E finalmente, vamos criar os arquivos jsp. O arquivo index.jsp servirá pra fazer as chamados ao servlet e o arquivo hello.jsp irá mostrar o resultado do servlet.

Conteúdo do arquivo index.jsp:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
  <meta name="author" content="Rodrigo Lazoti"/>
  <title>First Java EE 6 Example</title>
</head>
<body>
  <p><a href="hello">Execute Servlet (GET)</a></p>

  <hr width="100%" noshade="noshade"/>

  <form action="hello" method="post">
    <p>Name:<input type="text" name="username"/></p>
    <p><button type="submit">Execute Servlet (POST)</button></p>
  </form>
</body>
</html>

E o conteúdo do arquivo hello.jsp:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
  <meta name="author" content="Rodrigo Lazoti"/>
  <title>First Java EE 6 Example</title>
</head>
<body>
  <h2>Result: ${requestScope.message}</h2><br/>
  <h3>This servlet was executed ${requestScope.amountOfRequests} time(s).</h3><br/>
  <hr width="100%" noshade="noshade"/>
  <h4><a href="index.jsp">Back to main page</a></h4>
</body>
</html>

Pronto, nosso exemplo já esta pronto e pode ser testado. Com vimos algumas novidades como:

  • Interface local e remota são opcionais no EJB 3.1.
  • No EJB 3.1, vôce pode empacotar seus EJB’s em arquivos WAR junto com componentes da camada web. Você não precisa ter sua classes EJB definidas em um arquivo ejb-jar.
  • Agora as annotations podem ser usadas em mais tipos de componentes Java EE e o conjunto de anotações usados para injeção de dependência foi padronizada.
  • Ao invés de criar deployment descriptors, você pode anotar as classes para especificar que ela é um servlet.

Este exemplo criado está disponível no github: http://github.com/rlazoti/tutorial-javaee6-first-project

Descobrindo as exceptions encobertas pelo ADF Faces

Atualmente estou desenvolvendo um sistema utilizando ADF Faces na IDE da Oracle JDeveloper 10.1.3.4 e passei por um problema interessante. Estava ocorrendo um problema na minha aplicação mas não era gerado nenhuma exception no console, onde após determinada ação da aplicação era impresso no console apenas:

15/01/2009 17:32:31 oracle.adf.controller.faces.lifecycle.FacesPageLifecycle addMessage
WARNING: JBO-29000: null

Mensagem muito interessante e muito muito muito explicativa, não acham !?! :D

Depois de muito pesquisar, acabei encontrando uma forma de exibir o que ocasionou o JBO-29000 e é bem simples de implementar, a idéia principal é sobrescrever o métdo addMessage da classe FacesPageLifecycle e utilizá-la como o novo ADFPhaseListener do projeto.

Primeiro vou extender a classe FacesPageLifecycle e sobrescrever o metodo addMessage para ter o novo comportamento (mostrar a exception):


package br.com.rodrigolazoti.view.adf;

import javax.faces.context.FacesContext;
import oracle.adf.controller.faces.lifecycle.FacesPageLifecycle;
import oracle.binding.AttributeBinding;

public class MyPageLifecycle extends FacesPageLifecycle {

protected void addMessage(FacesContext context, AttributeBinding binding, Throwable error) {
super.addMessage( context, binding, error );
//aqui mostro o erro no console, log4j ou onde preferir
error.printStackTrace();
}

}

Agora eu extendo a classe ADFPhaseListener e retorno a minha classe criada acima ao invés de retorna a FacesPageLifecycle padrão do ADF:


package br.com.rodrigolazoti.view.adf;

import oracle.adf.controller.faces.lifecycle.ADFPhaseListener;

import oracle.adf.controller.v2.lifecycle.PageLifecycle;

public class MyPhaseListener extends ADFPhaseListener {
protected PageLifecycle createPageLifecycle() {
return new MyPageLifecycle();
}
}

Agora basta subistituir o ADFPhaseListener original pelo criado acima no arquivo de configuração do JSF (faces-config.xml):

<pre class="code"><lifecycle>
<phase -listener>br.com.rodrigolazoti.view.adf.MyPhaseListener</phase>
</lifecycle></pre>

Com isso foi fácil descobrir o motivo da mensagem e o que estava acontecendo de errado na aplicação. ;)