Resolvendo o problema de ‘is locally modified’ no plugin SCM do Maven com CVS

Enfrentei problemas ao configurar um build automatizado no Continuum via Maven 2.2.1 onde um dos goals era a execução do plugin SCM para aplicar uma tag (scm:tag) no CVS (acredite, ainda usam CVS por aí). No momento de passar a tag o CVS alegava para o Maven que alguns arquivos estavam localmente modificados (‘… is locally modified’), e a Build era terminada com falha.

No meu caso, os tais arquivos modificados eram arquivos .jasper gerados pela execução anterior de outro plugin, o do Jasper Reports, que compilava arquivos jrxml e os colocava em pastas do source ao invés de afetar apenas o pacote final na pasta target.

Para resolver, configurei uma exclusão de arquivos .jasper no plugin SCM da seguinte forma:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-scm-plugin</artifactId>
   <version>1.5</version>
   <configuration>
      <exludes>**/*.jasper</excludes>
   </configuration>
</plugin>

Review do Livro “Aplicações Java para Web com JSF e JPA” de Gilliard Cordeiro

Em 2012 assumí a disciplina de Tópicos Especiais em Análise e Desenvolvimento de Sistemas na faculdade em que leciono. Por se tratar de uma disciplina do último período do curso, encarei ela como uma “última chance” de resgatar os alunos, ao invés de simplesmente abordar assuntos complexos diversos como é de costume em disciplinas de Tópicos Especiais. Queria deixar algo de legal para os alunos levarem para o mercado de trabalho logo em seguida, já agregando ao currículo. Como o curso escolheu Java e eles já tinham visto algo de Desenvolvimento Web em JAVA em semestres anteriores, decidi abordar os frameworks JSF 2 e JPA 2, muito requisitados pelo mercado. No entanto, para tocar o curso precisaria de literatura em português para me apoiar, tendo em vista que não poderia exigir o inglês dos alunos (faz parte…).

Qual não foi minha Surpresa de descobrir duas grandes coisas: a editora Casa do Código, que como ela mesmo se entitula publica “livros de programadores para programadores”; e dentre os seus títulos descobri também uma grande preciosidade, o livro “Aplicações Java para Web com JSF e JPA” de Gilliard Cordeiro. O que me chamou a atenção foi: o livro aborda duas tecnologias que geralmente andas juntas; é em português, melhor, foi escrito por um brasileiro (já traduções nem sempre carregam o estilo do escritor original); o preço é convidativo, inclusive dando opção de comprar apenas a versão digital por uma pechincha; o tamanho do livro é razoável, considero pequeno, 275 páginas, exigindo apenas alguns minutos por dia para terminar de ler o livro em poucas semanas (essencial para indicar para alunos!)

Adquirí um exemplar e lí. Gostei bastante da escolha didática do livro que faz questão de elucidar como as coisas eram antes do JSF e do JPA e o motivo de cada dessas tecnologias terem entrado no jogo. Essa visão ajuda o leitor a compreender os frameworks não apenas como uma caixa preta a ser dominado mas sim como algo fruto de um design que evoluiu junto com a comunidade de desenvolvimento em torno do Java e de suas tecnologias. Destaco a introdução onde diagramas demonstram a evolução do código de um Servlet puro sem separação nenhuma de lógica de apresentação, negócio e persistência até atingir padrões mais atuais de design, justificando muita coisa repetida sem explicação por muitas equipes.

O livro não se propõe a ser um guia definitivo de JSF e JPA, e assim sendo, não entra em muitos detalhes tal como uma bíblia. Mas sua leitura provê o necessário para desenvolver uma aplicação web completa envolvendo aspectos diversos além do básico tais como segurança e performance. Considero uma excelente leitura para quem já programa em Java e desconhece os dois frameworks ou mesmo quem já programa em JSF mas ainda se sente perdido com conceitos fundamentais tais como o ciclo de uma requisição no JSF, o uso dos componentes básicos JSF, o uso de Ajax com o JSF. Já na parte de JPA, destaco as discussões diversas sobre performance seja ao abordar carregamento preguiçoso (lazy), mapeamento ou o problema das N+1 queries, o que pode embasar até mesmo desenvolvedores experientes na tomada de decisões em seus projetos.

Em resumo, gostei bastante da abordagem livro. Mais tarde também adquirí exemplares de outros títulos relacionados com Java da Casa do Código, dentre eles: Design Patterns, JSF Eficaz, Test-Driven Development, e o recém lançado CDI. Todos são livros relativamente pequenos mas com conteúdo denso, destinados realmente para programadores. Fica a dica!

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 {
    ...
}

JSF 1.2: Forçando a recriação de um Managed Bean

A configuração do escopo de ManagedBeans no JSF 1.2 é um tópico que gera bastante confusão. Além de poder definir se o ManagedBean vai ter um ciclo de vida atrelado do Request, Sessão ou Aplicação, existem outros modificadores como o @KeepAlive do RichFaces.

O fato é que essa farofa de escopos misturados com recursos de outras bibliotecas trazem algumas situações indesejadas. Seja em sistemas legados ou seja quando estamos em equipes muito heterogêneas, onde não dá pra garantir um bom planejamento do escopo correto de um MB, pode acontecer de você desenvolver uma solução considerando que o ManagedBean vai ser criado e inicializado ao acessar uma determianda tela, mas ao executar a aplicação, descobre erros que advém do fato do ManagedBean estar sobrevivendo na memória, sendo difícil perceber seu real ciclo de vida. Nesse instante, pode surgir a necessidade da recriação de um Managed Bean, evitando vários problemas.

A dica é implementar um método que será acionado por um commandButton ou commandLink da sua aplicação e que, ao invés de navegar diretamente para uma tela, obterá o ManagedBean via EL (no exemplo abaixo a classe DestinoMB), criará ele novamente, e em seguida chamará a tela desejada:

public class OrigemMB(){
	...
	public String onClickMeuBotao(){				
		FacesContext context = FacesContext.getCurrentInstance();
		ELContext elContext = context.getELContext();
		String elMB = "#{destinoMB}"; // Você deve conhecer a EL do seu MB
		
		ValueExpression expression = context.getApplication().getExpressionFactory()
			.createValueExpression(elContext, elMB, DestinoMB.class);
		expression.setValue(elContext, null);

		//Se necessário é possível ainda obter o MB para incializações
		DestinoMB destinoMB = (DestinoMB) context.getApplication().getExpressionFactory()
			.createValueExpression(elContext, elMB, DestinoMB.class).getValue(elContext);
                destinoMB.inicializar();
			
		return "outcomeDaTelaDesejada";
	}
	...
}

Resolvendo problemas com caracteres especiais UTF-8 no JSF 2

As aplicações JSF 2 que crio e faço deploy no Jboss 7 AS / 6 EAP sempre apresentam problemas de encoding no envio de campos de formulários. Forçar o encoding do XHTML, do form, e outros truques parece não resolver pois alguém no meio do caminho entrega os caracteres especiais já estragados para o servidor.

Pesquisando, descobri que se trata de uma configuração do Servidor de Aplicações, no meu caso o Jboss. Uma maneira mais garantida de resolver o problema, sem apelar para configurações do próprio servidor, é garantindo que todo request que chega para a aplição está com o encoding correto, no meu caso UTF-8. Para tanto, um bom e velho filtro resolve, como segue:

...
@WebFilter("*.jsf")
public class CharacterEncodingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
      throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }
}

O perigo da Deep Web

Após ouvir falar da Deep Web resolví verificar do que se tratava. O conceito é simples: existe uma parte da web que pode ser visualizada, já que foi indexada por importantes sites de buscas ou pode ser alcançada a partir de links de sites populares e é chamada de Surface Web (Web da Superfície); existe também uma parte da web que não pode, ou não deseja, ser alcançada, e é chamada de Deep Web (Web Profunda). Teoricamente um site da Deep Web nunca deveria ser alcançado, senão por alguem que guarde seu endereço “desconhecido” e não dependa de terceiros para chegar até ele.

Associado a esse conceito simples, há todo um movimento por navegar de forma anônima na web e acessar sites com conteúdo ofensivo ou proibido. Mas o que uma coisa tem a ver com a outra? Esse tipo de site não sobrevive na Surface Web. Os mecanismos de busca penalizam tais sites e deixam de listá-los, geralmente por questões legais ou denúncias. Da mesma forma, sites de hospedagem, plataformas de blog e outros meios de divulgação de conteúdo na Web deixam bem claro em seus termos de compromisso que não se pode veicular nenhum tipo de conteúdo ilegal ao utilizar o serviço. Sendo assim, um site que por exemplo se propõe a ensinar a fabricar bombas, cometer suicídio ou promover a pedofilia, naturalmente não tem vez na Surface Web e acaba sendo banido rapidamente. Isso se dá pois alguém tem que se responsabilizar pela ilegalidade.

É justamente aí que entra o lance do anonimato na rede. Havendo uma forma de utilizar a web sem que ninguem saiba quem são os donos e os visitantes dos sites, abre-se caminho para uma Web sem-lei, onde é difícil incriminar alguém. Dessa forma, esses sites tentam existir em uma outra Web, onde é bem mais difícil saber quem são os “culpados” pelos atos ilícitos. Curiosamente, os usuários assumiram que essa outra Web, anônima, seja também a Deep Web. Mas há diversas discussões filosóficos em torno do assunto, pois anonimato e alcance de sites são conceitos disintos, mas que parecem andar juntos. Percebam uma tendência estranha: existe uma web visível, e existe uma web invisível. De certa forma, os fatos mostram que tudo que é “legal”, acaba sendo visível, pois as pessoas podem acessar, podem referenciar, os buscadores podem listar, sem problemas com a lei. Naturalmente, o que sobra na parte “invisível”, são as coisas ilegais. E para “ver” essa parte “invisível”, as pessoas preferem navegar de forma anônima, já que o risco de esbarrarem em algo ilegal é grande. Eis o elo!

Um dos pilares tecnologicos que faz essa Deep Web (ou a Web Anônima) existir é o projeto TOR (https://www.torproject.org/). TOR é uma tecnologia que faz com que toda sua ação na web seja mascarada por camadas e mais camadas de criptografia. Fica praticamente impossível computacionalmente falando descobrir a origem de um acesso feito a um site. O projeto é mantido com intuito de promover a navegação anônima, com um tom de “protesto”, alegando que não deveriamos ser rastreados e defendendo a liberdade.  Naturalmente, a tecnologia caiu nos braços de malfeitores que a utilizam para criar uma Web paralela, anônima, que tem sido associada ao conceito de Deep Web por permitir acesso a conteúdos bizarros, onfensivos, ilegais, que nunca seriam encontrados por vias comuns como Google.

Afim de verificar a “propaganda” (nada boa) dessa Deep Web, baixei o navegador do TOR e acessei alguns sites com listagens de links da Deep Web (perceba que nesse momento, deixou de ser Deep, pois está escancarada). Infelizmente, não se vê muita coisa útil, e, para piorar, ao visitar os links você acaba esbarrando em muita coisas ruins como: venda de drogas, contratação de crimes, pornografia, bizarrices, coleções de fotos de atrocidades, auto-mutiliação, e muitos outros assuntos que, francamente, não precisariam ser acessados por ninguém que deseja se manter dentro da lei e em bom estado de sanidade mental.

Se por um lado achei a tal Deep Web apenas um conceito teórico simples, na prática concluí que não se trata de coisa boa. O tal discurso da liberdade e do anonimato acaba sendo uma ferramenta que permite que crimes como a pedofilia sejam incentivados. Que liberdade é essa que envolve a vida de inocentes? Se algo nao é bom para ser feito/dito na vida real, porque ela deve ser publicada no mundo virtual? Enfim, discussões mil podem ser feitos em cima dessa tal “liberdade” que acaba sempre sendo utilizada de forma errada…