Teste unitário com múltiplas threads no JUnit

Em um projeto que participo, há um conjunto de EJBs stateless reponsáveis por atender chamadas. Foi preciso disponibilizar para todas as camadas um contexto de mensagens cujo escopo é uma chamada ao serviço. Como não seria possível usufruir de um bean com escopo de Request, que exigiria trabalhar com beans stateful, simulei esse contexto através de ThreadLocal. Conforme a teoria, esse recurso “provides thread-local variables (…) each thread has its own, independently initialized copy of the variable.

Por ser um ponto crítico do sistema, desejei criar um teste automatizado para garantir o comportamento ao longo das mudanças. Em linhas gerais, o teste deveria criar várias threads utilizando seus contextos de mensagens e certificar que eles não se sobrepusessem. Durante a prospecção soube que o framework TesteNG fornece a opção de testes com múltiplas threads, mas julguei que seria um teste muito simples para precisar de uma biblioteca adicional.

Dessa forma, meu teste com JUnit da seguinte forma:

import org.junit.Assert;
import org.junit.Test;

public class ContextoTest {

    private static final int QTD_THREADS = 1000;

    @Test
    public void contextoDeveSerExclusivoDaThread() throws InterruptedException {

        Thread[] threads = new Thread[QTD_THREADS];
    
        // Cria e roda as threads
        for (int i = 0; i < QTD_THREADS; i++) {
            threads[i] = new ThreadTeste();
            threads[i].start();
        }

        // Aguarda a execução de todas das threads
        for (Thread t : threads) {
            t.join();
        }
    }

    class ThreadTeste extends Thread {

        @Override
        public void run() {
            Contexto.inicializar();

            // Dorme por um tempo aleatório para forçar paralelismo
            esperarUmTempoAleatorio();

            // Adiciona o nome da thread corrente no contexto
            Contexto.adicionarMensagem(Thread.currentThread().getName());

            // Contexto deve ter apenas 1 mensagem, contendo nome da thread
            Assert.assertEquals(1, Contexto.getMensagens().size());
            Assert.assertEquals(Thread.currentThread().getName(), Contexto.getMensagens().get(0));
        }

        private void esperarUmTempoAleatorio() {
            try {
        	Thread.sleep((long) (1000 * Math.random()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Um ponto interessante é introduzir algum grau de desordem no paralelismo, oque foi feito fazendo a thread dormir por um tempo aleatório antes de realizar o teste. Além disso, é primordial fazer join() das threads criadas ao fim do teste unitário para certificar que o JUnit não prosseguirá para outros testes enquanto ainda existem threads rodando do teste atual.

Configurando um projeto mínimo com Drools 6 no Maven

Em um projeto que participo surgiu a necessidade de utilizar um motor de regras de negócio para fornecer ao cliente a possibilidade de gerenciar as regras de um processo por conta própria. Como o sistema é em Java, o Drools, mais especificamente o sub-produto Drools Expert, se mostrou uma opção interessante, principalmente pela possibilidade de criar uma Linguagem Específica de Domínio (DSL).

Ao estudar a ferramenta na Web, percebi uma vasta gama de tutoriais, cada um com sua forma de criação e configuração do projeto, muitas vezes ainda apegado a versões inferiores a 6 da ferramenta.

Apresento aqui uma forma bem enxuta, usando o Eclipse como IDE e o Maven como gerenciador de dependências e builds:

1. No Eclipse, criar um projeto Maven, pulando a seleção de arquétipo.

2. No pom.xml do projeto, colocar como dependências o drools-compiler, bem como uma biblioteca de log compatível com SLF4J (sugiro a Logback), conforme o trecho abaixo:

	<dependencies>
		<dependency>
			<groupId>org.drools</groupId>
			<artifactId>drools-compiler</artifactId>
			<version>6.3.0.Final</version>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.1.5</version>
		</dependency>
	</dependencies>

3. Sugiro ainda que no pom.xml você determine como configuração de build a versão do Java desejada, aqui no caso a 1.7. Para isso faça conforme o trecho abaixo:

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.5</version>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

2. Acionar botão direito no projeto, Maven > Update Project para que o Eclipse perceba as novas configurações

3. Criar o arquivo src/main/resources/META-INF/kmodule.xml com o conteúdo:

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule" />

4. Criar o arquivo src/main/resources/regras.drl com o conteúdo:

rule "olá"
	when
		$texto : String()
	then
		System.out.println("Olá "+$texto);		
end

5. Criar uma classe executável para testar. Ex:

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class Main {
	
	public static void main(String[] args) {
		
		KieServices ks = KieServices.Factory.get();
		KieContainer kcontainer = ks.getKieClasspathContainer();				
		KieSession ksession = kcontainer.newKieSession();
		
		String texto="Rafael";		
		ksession.insert(texto);
		
		ksession.fireAllRules();				
	}
}

6. Se desejar utilizar o plugin do Drools no Eclipse, que facilita algumas tarefas mas não é essencial, instale os artefatos desejados do update site:
http://download.jboss.org/drools/release/6.3.0.Final/org.drools.updatesite/

No meu github coloquei um exemplo completo de Drools usando tanto DRL (linguagem de regra do Drools) e DSL (linguagem específica de domínio) para aplicar regras de negócio num exemplo de carrinho de compras com descontos no preço e no frete: https://github.com/rafaelodon/poc-drools

10 anos com Java. Relembrando…

Hoje me dei conta que há exatos 10 anos atrás, em agosto de 2004, tive meu primeiro contato real com o Java. Apesar de nesses 10 anos não ter trabalhado apenas com Java, ela foi meu principal “ganha-pão”. Nesse post faço uma volta ao passado para relembrar como eram as coisas nessa época.

Começei a programar muito novo, ainda criança, brincando de mover a tartaruguinha do Micromundos com Linguagem Logo. Na pré-adolescência e início da adolescência brincava muito com Basic e Pascal, tudo console, e mais pra frente Visual Basic, Delphi já no Win 32. E foi no ensino-médio técnico que a coisa ficou séria, quando aprendí C/C++ e o bom e velho PHP com pacotão Web (HTML+CSS+JavaScript), garantindo meus primeiros freelances. Mas foi só em agosto de 2004, quando inciei a graduação em Ciência da Computação, que me enfiaram o Java goela abaixo pela primeira vez. Era uma recomendação da SBC na época. As universidades todas seguiam tal tendência, já que era uma plataforma livre e o mercado de Java na época estava quente.

E assim, durante a graduação usei Java para tudo: construir aplicativos console, desktop, web e mobile; exercitar o conceito de cliente/servidor e técnicas de arquitetura paralela e distribuída; estudar algoritmos, estruturas de dados, grafos, orientação por objeto e quase todas os assuntos que envolviam programação no curso. E apesar de diversos trabalhos enquanto estudante, foi só em 2007 que tive meu primeiro contato realmente profissional com Java em uma empresa de desenvolvimento.

Em 2004 Java era um terreno ainda em exploração. Estávamos na JDK 1.4, mas muita gente ainda usava a 1.3. Ainda falava-se muito em Java applets como uma grande vantagem, mas ele já havia definitivamente perdido espaço para o Flash. De fato muito sites corajosos (não eram só os sites de banco) usavam applets para alguns propósitos, principalmente interativos. Java Desktop também era muito bem visto, mas ainda havia muita referência baseada em AWT ao invés do SWING. Java FX nem sonhava em existir! E como essa história de levar tudo para a Web ainda estava acontecendo (e o Java EE teve papel importante no patrocínio dessa transição), teve muito manolo que optou por fazer sistemas desktop cliente/servidor enormes, com muito RMI (o RCP do Java), ao invés de partir para o uso de EJBs. Aliás, EJB foi um recurso arquitetural nobre que o Java incentivou desde muito cedo e que até hoje é sub-utilizado, dando lugar para soluções com desenhos vergonhosamente pouco sofisticados.

Lembro-me também da hype sobre Java ME e das promessas sobre o Mobile, muito antes dessa realidade dos Smartphones atuais. Os professores e evangelizadores da tecnologia falavam muito sobre a questão do Java ser multi-plataforma e de poder ser usado em aplicações embarcadas de hardwares específicos. Mas acho que pouca gente teve contato com essa parte. Quem carregou o Java pra frente no Mobile foi a Nokia em sua época de ouro. Suporte ao Java era uma feature a ser observada na compra de um aparelho novo. Cheguei a ver inúmeras vagas de emprego de empresas que faziam aplicativos para celular, e tenho ainda conhecimento de alguns colegas que participaram de soluções de software corporativas baseada em outros Handhelds que usavam Java, como os Palm.

Pra fechar, destaco o Java EE, que julgo ter sido a perna do Java que mais cresceu. Em 2004 quem soubesse Servlet e JSP básico já era disputado pelo mercado. O conceito de MVC ou o simples conceito de divisão em camadas despontava como tendência, e quem diria que iria durar tanto tempo. Mas pouco se falava de JSF e muito menos de Spring. O que alguns usavam era o Struts para ajudar com o vai-e-vem dos servlets. A efervescência dos frameworks ainda iria começar: muitos surgiram e muitos desapareceram. E alguns viraram especificação! Algumas soluções de ORM existiam, e o Hibernate ainda não era unanimidade (muito menos existia JPA). Lembro de dar manutenção em um projeto que usava Apache IBatis p/ ORM (nunca mais ouví falar). Aliás, unanimidade mesmo era que precisávamos de muito XML pra fazer qualquer coisa em projetos web. Annotations só vieram na JDK 1.5…

Fica a saudade dessa época onde o Java era uma terra de oportunidades e uma grande novidade. O legado deixado é enorme, o que me leva a crer que vamos demorar a deixar de escutar o nome “Java” por aí (seria o novo Mainframe?). Há ainda quem diga que se tornou uma ferramenta implacável no cinto-de-utilidades do programador, ao lado do C/C++ por exemplo (todos anos a fio no Top 5 do Ranking TIOBE). Por fazer parte da minha história, torço para que a plataforma continue se adequando aos novos ventos e gerando oportunidades!

Abandonando o antigo formulário j_security_check através de JSF 2 e Servlet 3

Muitas são as aplicações web em Java que utilizam o Serviço de Autenticação e Autorização do Java (JAAS) para fazer a segurança. E um elemento famoso no JAAS é o JSP/HTML de login que possui um formulário mágico que faz um POST para a URL “j_security_check“, enviando o password e a senha através dos inputs de nome “j_password” e “j_username” respectivamente. Muitos torcem o nariz para esse tipo de coisa, já que a plataforma está de certa forma engessando a tela de login.

As vantagens de querer fazer um formulário de login JSF 2 são muitas! Primeiramente você pode querer herdar o layout de um template via Facelets. Você pode também querer utilizar componentes ricos de bibliotecas como PrimeFaces ao invés de simples inputs HTML padrão. O JSF também dá um bom suporte para validação de campos e mensagens de erro/sucesso. Mas dadas as restrições impostas pelo j_security_check e seus amigos, como unir os dois mundos então?

Com a chegada do JEE 6 e a nova Servlet API 3.0, foi previsto um método bem óbvio na interface HttpServletRequest chamado request.login(String username, String password). O resto você provavelmente já imagina: pode-se acionar o JAAS programaticamente dentro de um ManagedBean do JSF por exemplo, unindo o melhor dos dois mundos.

A idéia então é fazer um XHTML de login e fazer um ManagedBean que cuide do comportamento dessa tela. Veja como fica a configuração de segurança do web.xml:

<?xml version="1.0"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" 
        xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
           http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	version="3.0">

	...
	
	<security-constraint>
		<web-resource-collection>
			<web-resource-name>private</web-resource-name>
			<description>private resources</description>
			<url-pattern>/private/*</url-pattern>
		</web-resource-collection>
		<auth-constraint>
			<role-name>*</role-name>
		</auth-constraint>
	</security-constraint>
	
	<login-config>
		<auth-method>FORM</auth-method>	
		<form-login-config>
			<form-login-page>/public/pages/security/login.jsf</form-login-page>
			<form-error-page>/public/pages/security/login.jsf</form-error-page>
		</form-login-config>
	</login-config>
	
	<security-role>
		<role-name>*</role-name>
	</security-role>

</web-app>

Perceba que no web.xml a página de login é tanto o formulário quanto a página de erro, ou seja, em caso de login inválido a aplicação retornará para a página de login, permitindo continuar interagindo com o formulário para exibir mensagens por exemplo. A página /public/pages/security/login.xhtml pode ser algo assim (observe que ela herda um template via Facelets):

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
	xmlns:p="http://primefaces.org/ui"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	template="/WEB-INF/template/main.xhtml">
	<ui:define name="body">
		<p:messages id="messages" globalOnly="true" />
		<h:form id="form">			
			<h:panelGrid columns="3">
				<p:outputLabel value="Usuário" for="inputUsuario" />
				<p:inputText id="inputUsuario" required="true"
					value="#{loginMB.usuario}" />
				<p:message for="inputUsuario" />

				<p:outputLabel value="Senha" for="inputSenha" />
				<p:password id="inputSenha" required="true"
					value="#{loginMB.senha}" />
				<p:message for="inputSenha" />
			</h:panelGrid>

			<p:commandButton id="btEntrar" value="Entrar" ajax="false"
				action="#{loginMB.onClickLogar()}"
				icon="ui-icon-check" />
		</h:form>
	</ui:define>
</ui:composition>

E um exemplo de ManagedBean para tal página pode ser (os imports estão omitidos):

...

@ManagedBean
@ViewScoped
public class LoginMB {

    private static final String PAGINA_INDEX = "/private/pages/index.xhtml";

    private String usuario;
    private String senha;

    public String onClickLogar() {
        try {
	    HttpServletRequest request = (HttpServletRequest) FacesContext.
                getCurrentInstance().getExternalContext().getRequest();
            request.login(this.usuario, this.senha);
            return PAGINA_INDEX;
        } catch (ServletException e) {
	    //se houver erro no Login Module vai cair aqui... 
            //Você pode fazer log por exemplo!
        } finally {
            //tratar aqui mensagens de segurança que possam ter vindo 
            //do Login Module exibindo-as na forma de FacesMessage
	}

        return null;
    }

    public String getUsuario() {
        return usuario;
    }

    public void setUsuario(String usuario) {
        this.usuario = usuario;
    }

    public String getSenha() {
        return senha;
    }

    public void setSenha(String senha) {
        this.senha = senha;
    }
}

Não se esqueça de que para esse recurso de login programático estar disponível, sua aplicação deve adicionar a dependência provida a API do Servlet 3.0 no pom.xml:

<dependency>
	<groupId>javax</groupId>
	<artifactId>javaee-web-api</artifactId>
	<version>6.0</version>
	<scope>provided</scope>
</dependency>            

Vale ressaltar que o exemplo do post cobre apenas o essencial. Para atingir a excelência num esquema de login JAAS é preciso cuidar de vários outros aspectos. Um deles é definir um bom mecanismo de troca de mensagens do Login Module para com a Aplicação. Uma opção é adicionar a mensagem como atributo no Request, podendo capturá-la no ManagedBean e tranformá-la em uma FacesMessage. Outra questão que deve ser observada é o comportamento da aplicação quando a página de login é acessada por um usuário já logado, podendo redirecioná-lo ou retirá-lo da sessão, o que pode ser feito via JSF adicionando no seu XHTML de login um event listener na fase de Pre-Render View e implementando um listener correspondente:

...
   <f:event listener="#{loginMB.verificaSeUsuarioJaLogado}" type="preRenderView" />
...

Tenho certeza que partindo dessa solução base você poderá buscar várias sofisticações, fugindo do tradicional JSP de login para o JAAS.

Resolvendo conversão automática para ZERO no JSF 2 com Jboss 7 AS / EAP 6

Tive um problema com JSF 2.0 onde se um campo mapeado para uma propriedade numérica não era preênchido, ao submeter o formulário ele era interpretado como zero. Isso me trouxe transtornos pois o campo era obrigatório, e zero era um valor válido.

Ainda que no meu caso específico fosse possível resolver definindo o campo como required ou mesmo criando um Validator que verificasse seu preenchimento, não fiquei satisfeito com a conversão automática feita pelo JSF, pois ela poderia afetar outros pontos do sistema

Descobri que no Jboss 7 AS / 6 EAP, que utiliza a implementação Mojarra do JSF e que também utiliza internamente o Tomcat como web container, é possível definir uma propriedade de sistema que desabilita essa conversão automática para zero. No entanto, como não teria sempre acesso aos ambientes onde a aplicação iria rodar, quis uma maneira programática de definir essa propriedade. Para tanto, adicionei a linha de código abaixo ServletListener da minha aplicação web. Veja:

@WebListener
public class MeuWebAppListener implements ServletContextListener
    ...
    @Override
    public void contextInitialized(ServletContextEvent event) {
        ...
        System.setProperty("org.apache.el.parser.COERCE_TO_ZERO", "false");
    }
    ...
}

Problema de falta de detalhes no Log / Console do Jboss AS 7 / EAP 6

Durante um bom tempo reparei que estava sem erros e detalhes da aplicação no Log e Console do Jboss AS 7 / EAP 6. O stack das exceções era exibido na tela do navegador mas não era impresso nem no console nem no arquvo de log.

Verificando minhas configurações de Logging do servidor e da aplicação, tudo estava normal. Tentei atacar o nível do Logging no console, mas não resolvia pois para ver os erros era preciso definir um nível muito baixo, praticamente impossível de filtrar o necessário.

Por fim, descobrímos na equipe que bastava adicionar o seguinte argumento na execução do Jboss:

 -Dorg.jboss.as.logging.per-deployment=false

Pra fazer isso via Eclipse com Jboss Tools, clique duas vezes sobre o servidor na aba Server, clique no link Open Launch Configuration e adicione o argumento mencionado no fim da caixa de texto Program Arguments.

Desabilitando um producer de terceiros no CDI

Entrei um problema no Jboss 7 AS / 6 EAP onde o WELD reclamou ainda no deploy da aplicão que existiam ambiguidade em uma injeção, devido a presença de dois produtores capazes de instanciar a mesma classe (no meu caso o FacesContext do JSF). Veja abaixo o erro:

org.jboss.weld.exceptions.DeploymentException: WELD-001409 Ambiguous dependencies for type 
     [FacesContext] with qualifiers [@Default] at injection point...

Para resolver precisei desativar um dos produtores. Isso foi feito criando uma Extension que veta o funcionamento de um produtor, no caso abaixo, do produtor org.apache.myfaces.extensions.cdi.jsf.impl.util.FacesInformationProducer do Apache MyFaces. Veja abaixo:

import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessAnnotatedType;

import org.apache.myfaces.extensions.cdi.jsf.impl.util.FacesInformationProducer;

public class FacesProducerSolverExtension implements Extension {

	public void observe(@Observes ProcessAnnotatedType p){
		if(p.getAnnotatedType().getJavaClass()
                    .equals(FacesInformationProducer.class)){
			p.veto();			
		}
	}
}

Para que esse extension funcione, ele deve ser registrado no arquivo de texto WEB-INF/classes/META-INF/services/javax.enterprise.inject.spi.Extension no seu WAR que ficará com o seguinte conteúdo:

br.gov.demoiselle.destdemoiselle.cgpolact.cdi.extension.FacesProducerSolverExtension

Resolvendo falta de classes para SSL do JDK no Jboss 7 AS / 6 EAP

No Jboss AS 7 / EAP 6 enfrentei uma situação onde quando a aplicação tentava estabelecer uma conexão segura via HTTPS (no caso era um webservice), acontecia o seguinte erro:

java.lang.NoClassDefFoundError: com/sun/net/ssl/internal/ssl/Provider

Pesquisando, percebí que essa classe fazia parte da própria JRE, mas no entanto, o Jboss não estava dando visibilidade dela para o ClassLoader da aplicação.

Para resolver, basta adicionar os seguintes path no arquivo XML do módulo da JDK localizado em JBOSS_HOME/modules/sun/jdk/main/module.xml:

...   
     <path name="com/sun/net/ssl/internal"/>
     <path name="com/sun/net/ssl/internal/ssl"/>
... 

Suprindo a falta do @KeepAlive no JSF 2

Para quem programa em JSF 1.2 com RichFaces + A4j, um recurso muito popular é o @KeepAlive. Anotando um ManagedBean dessa forma ele fica com um escopo maior que o de Request e menor que o de Sessão, sobrevivendo na memória enquando o usuário navegar entre páginas que façam uso de um mesmo ManagedBean. Exemplos clássicos: 1. Páginas de listagem e edição; 2. Formulários preênchidos em etapas.

Ao pisar no terreno do JSF 2.0 essa tag deixa de existir. Ainda que existisse, você pode não querer usar o RichFaces e escolher outra biblioteca, como por exemplo a PrimeFaces. A ausência do @KeepAlive no JSF 2.0 parece não ser vista como algo grave já que existem novas possibilidades de controle de escopo tais como as anotações próprio JSF e a as anotações do CDI. O JSF 2.0 fornece por exemplo a @ViewScoped, usada para páginas recheadas de Ajax, mantendo o ManagedBean vivo enquanto existem requests para a mesma página, ou seja, quando não há navegação (métodos acionados devem ser void ou retornar String null). Já o CDI fornece o @ConversationScoped que permite dizer quando a “conversação” com o ManagedBean inicia e termina de forma programática.

Para quem ainda sente falta do simples e preciso @KeepAlive, uma solução é recorrer ao pacote CDI Extensions (CODI) do projeto Apache MyFaces, que fornece a notação @ViewAcessScoped que nos dá exatamente o comportamente desejado. Para instalá-lo via Maven, adicione as seguintes dependências ao projeto:

<dependency>
	<groupId>org.apache.myfaces.extensions.cdi.modules</groupId>
	<artifactId>myfaces-extcdi-jsf20-module-api</artifactId>
	<version>1.0.3</version>
	<scope>compile</scope>
</dependency>

<dependency>
	<groupId>org.apache.myfaces.extensions.cdi.modules</groupId>
	<artifactId>myfaces-extcdi-jsf20-module-impl</artifactId>
	<version>1.0.3</version>
	<scope>compile</scope>
</dependency>

<dependency>
	<groupId>org.apache.myfaces.extensions.cdi.core</groupId>
	<artifactId>myfaces-extcdi-core-api</artifactId>
	<version>1.0.3</version>
	<scope>compile</scope>
</dependency>

<dependency>
	<groupId>org.apache.myfaces.extensions.cdi.core</groupId>
	<artifactId>myfaces-extcdi-core-impl</artifactId>
	<version>1.0.3</version>
	<scope>compile</scope>
</dependency>

Para usar a anotação no seu ManagedBean, faça como segue:

import br.gov.frameworkdemoiselle.stereotype.ViewController;

@ViewAccessScoped
public class MeuMB {
    ...
}