Criando um Ajax Loading no Angular usando Http e Observables

Quando fazemos uma requisição HTTP assíncrona em JavaScript (Ajax) é interessante dar um feedback visual, uma vez que que o navegador não dá nenhum. Aliado a isso, pode ser interessante também bloquear a tela para uso enquanto a requisição não retorna, evitando que o usuário clique em alguma coisa indesejada nesse período.

Nesse post vou demonstrar como fazer um Ajax Loading (aquela janelinha que geralmente diz “Carregando…“, “Loading…“, ou exibe um GIF girando) no Angular 2+. A solução apresentada evita que os pedidos de mostrar/esconder o Loading fiquem espalhados por diversos pontos do código, atuando diretamente na camada de chamada ao serviço Http, sem poluir o código de cada tela/componente. É possível que já exista alguma biblioteca ou componente pronto para isso, mas achei muito interessante registrar a solução pura pois ela aborda decisões de design de classes que podem inspirar a resolução de outros problemas parecidos.

Em linhas gerais, a idéia é simples:

  • Criar uma classe wrapper em torno da classe Http do Angular.
  • Criar um LoadingService cujo estado controla quando o Loading deve ser exibido ou escondido.
  • Criar um recurso visual no template raiz da aplicação que só é exibido quando o LoadingService indica positivo.

Existem outras abordagens possíveis para resolver essa situação, e elas serão discutidas no final do artigo.

Primeiramente vamos construir nosso LoadingService:

import { Injectable } from '@angular/core'

@Injectable()
export class LoadingService {

    private loading: number = 0;

    showLoading() {
        this.loading++;        
    }

    hideLoading(){
        this.loading--;
        if(this.loading < 0){
            this.loading = 0;
        }
    }

    isLoading(){
        return this.loading > 0;
    }
}

No código acima, basicamente, sempre que alguém chama showLoading(), incrementa-se 1 unidade numa propriedade numérica privada. Quando alguém chama hideLoading(), subtraímos 1 unidade. Essa estratégia foi feita pois podem ocorrer diversas requisições HTTP assíncronas, logo, o Loading deve ser exibido enquanto todas elas não terminarem, ou seja, quando esse número volta a ser zero. O método isLoading() permite observar se está ou não acontecendo alguma chamada.

Agora vamos trabalhar na nossa classe wrapper do Http. Um wrapper, como o nome já indica, é um Padrão de Projeto onde uma classe embrulha um objeto, permitindo adicionar tratamentos a esse objeto. O Angular já fornece através do módulo @angular/http uma classe para o programador fazer requisições HTTP do tipo GET/POST/PUT/DELETE, geralmente utilizado para fazer chamadas à API REST que dá suporte à aplicação. Essas chamadas na verdade retornam Observables, que são objetos que permitem ao chamador do método programar o que vai acontecer quando a chamada assíncrona termina. Vamos criar um wrapper chamado HttpService que embrulha o Http do Angular. Veja como fica o código:

import {Injectable} from '@angular/core';
import {Http, Response} from '@angular/http';
import {Observable} from 'rxjs/Rx';
import 'rxjs/add/operator/do';

import { LoadingService } from './loading.service';

@Injectable()
export class HttpService {

    constructor( private loadingService: LoadingService, private http: Http ) { }

    get(url: string): Observable<Response> {
        return this.watch(this.http.get(url));
    }  
    
    //fazer também para o post, put, delete ...

    private watch(response: Observable<Response>): Observable<Response> {

        this.loadingService.showLoading();

        return response.do(
            next => {
                this.loadingService.hideLoading();
            }, 
            error => {   
                //faça aqui seu tratamento de erro
                this.loadingService.hideLoading();
            }            
        );
    }
}

Observe no código acima que o tanto o Http quanto o LoadingService estão sendo injetados no HttpService. A classe deve oferecer métodos para GET/POST/PUT/DELETE, e esses métodos por sua vez delegam a chamada para os respectivos métodos do serviço Http do Angular. No entanto, perceba que quando vamos chamar o método get() do Http por exemplo, na verdade apenas passamos como parâmetro sua chamada para a função watch que irá adicionar um tratamento: antes de executar a chamada pedimos ao LoadingService para exibir o Loading; depois que a chamada é executada, seja com sucesso ou erro, perdimos para esconder o Loading. Esse tipo de chamada pode parecer estranho para quem não está habituado com a parte funcional do JavaScript, já que na verdade não estamos executando método algum, mas apenas anexando coisas à uma chamada que só será feita no futuro, quando de fato alguma código quiser fazer uma chamada a uma URL.

Agora falta preparar o tempalte raíz da aplicação para ter algum elemento visual que será exibido sempre que o LoadingService indicar que tem requisições. Para isso, basta incluirmos alguns controles no componente raiz da aplicação Angular. Veja o código abaixo:

import { LoadingService } from './loading.service';
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div id="loading" [class.hidden]="!loading">Loading...</div>
    <div>
      <h1>Angular Loading Test</h1>

      <child-component></child-component>

      <footer>by Rafael Odon (rafaelodon.com)</footer>
    </div>
  `,
  styles: [`
    .hidden{
      display: none;
    }

    #loading {      
      position: fixed;                  
      top: 0px;
      left: 0px;
      width: 100%;
      height: 100%;                           
      color: red;
      background-color: black;
      opacity: 0.5;
      font-size: 5em;      
      text-align: center;            
    }    
  `]
})
export class AppComponent {

  constructor( private loadingService: LoadingService ){}

  get loading(){
    return this.loadingService.isLoading();
  }
}

Observe primeiro o código da classe do componente e ignore o código do template HTML. A classe AppComponent injeta o LoadingService. Definimos a propriede chamada loading, que na verdade não é um atributo interno, mas apenas a definiçaõ de um get. Esse get na prática delega a obtenção dessa informação para o método isLoading() do nosso LoadingService. Com isso, tornamos possível que no nosso template HTML seja possível observar o estado do LoadingService.

No template HTML do componente raiz, basicamente você precisa criar um elemento visual que só é exibido se a propriedade loading do componente for verdadeira. Isso pode ser feito de várias formas. Eu fiz uma DIV que ganha a classe .hidden sempre que a propriedade loading é falsa. No CSS, defini que a classe .hidden esconde o elemento. Ademais, personalizei essa DIV no CSS para que ela ocupe toda a tela, com uma opacidade de 50%, bloqueando o usuário de clicar em outras coisas.

Com essa estrutura montada, qualquer código que que acione o HttpService, direta ou indiretamente, por consequência fará com que o Loading apareça. Veja o código abaixo um componente filho que foi criado para exemplo:

import { HttpService } from './http.service';
import { LoadingService } from './loading.service';
import { Component } from '@angular/core';

@Component({
  selector: 'child-component',
  template: `
    <button (click)="onClick()">Perform a slow request...</button>
    <p>{{message}}</p>
  `  
})
export class ChildComponent {
  
  message:String = "";

  constructor( private httpService: HttpService ){}

  onClick(){
    this.message = "";
    this.httpService.get("http://www.fakeresponse.com/api/?sleep=1").subscribe(
      next => this.message = "Done!"
    );
  }
}

Por fim, vamos ver como fica a configuração do módulo de aplicação:

import { HttpModule } from '@angular/http';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { HttpService } from './http.service';
import { LoadingService } from './loading.service';

import { AppComponent } from './app.component';
import { ChildComponent } from './child.component';

@NgModule({
  declarations: [
    AppComponent,
    ChildComponent    
  ],
  imports: [
    BrowserModule,
    HttpModule
  ],
  providers: [    
    HttpService,
    LoadingService
  ],
  bootstrap: [AppComponent]
})
export class AppModule {

}

Perceba que estamos importando o módulo HttpModule, já que, no fundo no fundo, as chamadas HTTP da aplicação passam por esse recurso nativo do Angular. Mas estamos provendo para toda a aplicação o HttpService. A idéia então é, quando for necessário fazer uma chamada assíncrona HTTP que exiba o Loading, utilize o HttpService ao invés do Http nativo do Angular.

Alguns podem questionar se não seria possível herdar o Http ao invés de injetá-lo dentro de um wrapper. É uma questão de escolha. Mas ao usar herança será preciso configurar no Angular a sua sub-classe criada como uma alternativa a ser provida no lugar da outra. Uma outra alternativa que tem sido muito apresentada para resolver problemas parecidos é o uso de Interceptors HTTP, mas no entanto isso faz com o que o tratamento dado na interceptação da requisição HTTP sempre aconteça, exigindo algumas manobras para torná-lo condicional. Ao resolver o Loading via wrapper, além de simples, fica mais fácil para o programador decidir quando usar ou não os tratamentos criados.

Um detalhe importante dessa solução é que o Angular provê a mesma instância do LoadingService para toda a aplicação. Como declaramos o LoadingService no módulo da aplicação, ele funcionará como um singleton, conforme é explicado na própria documentação. Isso garante que o estado desse serviço (o número interno que incrementa e decrementa) seja compartilhado e acessado de qualquer ponto da aplicação.

O código completo pode ser visto em: https://github.com/rafaelodon/angular-loading

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

O Ciclo de Sabotagem das Tecnologias de Desenvolvimento de Software

Esses dias eu estava super cliché, meio crítico com o fato de surgir tanta tecnologia nova o tempo todo. Praticamente a cada 4 anos a gente precisa se renovar para não ter o aspecto técnico do currículo anulado nos 4 anos seguintes. Tudo bem que muitas dessas novidades advém de um movimento natural promovido pelas grandes inovações (desenvolvimento mobile por exemplo). Mas é comum assistir tecnologias morrendo e dando lugar a outras que produzem o mesmo resultado, sem justificativas convincentes.

Por um instante cheguei a formular a hipótese que na verdade isso era um fenômeno de procrastinação coletiva promovido pelo [in]consciente coletivo dos profissionais de TI, que acham super recompensador gastar seu tempo tendo que reaprender como fazer o mesmo de forma diferente. Talvez tenha um pouco disso também. Mas pensando melhor, percebo também um padrão de sabotagem  que é descrito no ciclo abaixo:

#1 –  The dawn of man: Surge uma Nova Tecnologia ®, ainda incipiente , mas que promete suprir uma deficiência do ferramental vigente.

#2 – O buzz: A Nova Tecnologia ® atrai a atenção de acadêmicos e entusiastas que se aproveitam do pioneirismo para surfar na crista da onda, publicando em revistas, palestrando em eventos, etc. Mas tudo se resume ao buzz. O mercado corporativo ainda olha com desconfiança.

#3 – Mordendo a maçã: Versões novas são lançadas, boas práticas são disseminadas, cursos, artigos, tutoriais, tópicos em fóruns, perguntas e respostas saturam a web. Convencidos pelos gurus, vai surgindo na manada de profissionais espectadores o desejo de adotar a Nova Tecnologia ®, tanto pelo prazer de aprender algo novo quanto pela necessidade de manter seus currículos atualizados.

#4 – As invasões bárbaras: Com o mercado de trabalho recheado de defensores da Nova Tecnologia ®, corporações de impacto passam a adotá-la em projetos relevantes que apresentam desafios reais, em escala real. E esses projetos introduzem um outro fator crucial: a pressão por prazo. Prazo leva à pressa que leva ao aumento de recursos. Nesse clima, uma manada de profissionais sub-qualificados e por vezes sub-remunerados, forçam pro-ativamente o uso indiscriminado da Nova Tecnologia ®. Tudo é resolvido da forma mais imediata o possível, com muita gambiarra, sem avaliar alternativas, sem conhecer recursos avançados, buscando resultados rápidos que salvem o projeto (e também seus empregos). Julgando-se produtivos e confortáveis com a Nova Tecnologia ®, está formado um batalhão de martelos que acha que tudo é prego.

#5 – Sodoma e Gomorra: Com o colapso de grandes projetos que adotaram a Nova Tecnologia ®, começam a sair cases de insucesso, artigos que condenam seu uso e o famoso anúncio: “a Nova Tecnologia ® morreu“. Por mais que os gurus afirmem que são os profissionais que usaram de forma errada, e que as novas versões incluam recursos que suprem as deficiências e introduzem melhorias, a tecnologia continua estigmatizada por suas restrições conceituais e efeitos colaterais do uso costumeiro.

#6 – Let’s twist again: Volte ao Passo #1.

Arquiteto ou apenas bom desenvolvedor?

Sempre fui crítico com o rótulo arquiteto de software. Se a gente parar pra pensar, é um nome um tanto quanto mal escolhido. Na engenharia civil, o arquiteto é o desenhista do prédio, o artista do concreto. Oscar Niemeyer rabiscava formas modernistas no papel e pouco se importava em como aquilo viraria realidade, o que de fato seria um problema para os engenheiros.

Esboço de Oscar Niemeyer
Esboço de Oscar Niemeyer

Já na área de software, quem costuma imaginar coisas difíceis de por em prática é o cliente, o demandante. Para executar suas idéias mirabolantes há de se contar com super-heróis capazes de eleger plataformas, tecnologias, protocolos, padrões, componentes, topologias e de projetar como isso tudo vai conversar. O curioso é que o nome que se dá para esse super-herói é justamente arquiteto de software.

Eu particularmente acredito que essas atribuições sejam apenas a descrição de um bom desenvolvedor, ou para ser mais justo ao argumento, um bom engenheiro de software. O curioso é que quase não se vê o termo engenheiro de software circulando em vagas de emprego no mercado brasileiro. Acredito que isso se dê por alguns fatores.

O primeiro deles advém da própria distinção que os desenvolvedores gostam de ter em relação às demais engenharias. Há todo um brio envolvido no domínio da arte de desenvolvedor sistemas, principalmente quando você fica anos estudando muito além da programação. Talvez não queiramos ser confundidos com engenheiros civis ou mecânicos. Enquanto isso, na mão contrária do nosso ego, o mercado de trabalho acha ótimo que nos consideremos apenas desenvolvedores, uma vez que engenheiros tem conselho, piso salarial e algum respeito perante a sociedade. Engenheiros constroem prédios. Nós “mexemos” com informática.

Mas então, se formamos uma manada de desenvolvedores egocêntricos, quem são os famosos arquitetos de software? Pessoalmente ainda acho que um arquiteto é nada mais nada menos que um bom engenheiro de software, com experiência, senso crítico e visão micro e macro sobre a pilha de tecnologias envolvidas num sistema. O que percebo é que os que se dizem arquitetos buscam nesse rótulo uma distinção, não querem ser confundidos com meros programadores, uma atividade mais básica. Da mesma forma, os desenvolvedores também não querem se responsabilizar por decisões que irão assombrar o projeto pelo resto dos dias, podendo trazer impactos diretos na performance e disponibilidade do sistema. E é nesse contexto que a arquitetura de software vai se tornando ocultista e mística, fazendo com que os programadores se distanciem do que deveria ser o grande objetivo: se tornar um excelente profissional.

Abandonando os rótulos, o fato é que todo sistema desenvolvido terá uma arquitetura, quer você queira ou não. Cabe a você deixar de ser um simples fabricador de telas e querer absorver e contribuir com as decisões técnicas dos projetos em que você colabora. Busque formar o tal senso crítico, viver experiências, conhecer e experimentar as tecnologias de forma contínua. Não perca de vista o norte da excelência, independente do nome que eles inventam para ela.

O Ócio Nocivo nas Redes Sociais

Aqui vou eu fazer um post criticando os posts da Internet. Mas creio ser uma contradição razoável.

Talvez você, assim como eu, esteja sentindo mais desprazer do que prazer ao usar as redes sociais. Mas antes de abonimá-las, lembremo-nos de que o mal quase sempre está no homem, nunca nas coisas. O pai da aviação, Santos Dumont, suicidou-se aos 59 anos, angustiado por ver seu invento usado em guerra. E nós? Que uso estamos dando para esse ambiente moderno de fácil comunicação que é a Internet? Sob essa luz lanço um desafio: vamos trocar esse novo vício de ficar contemplando por horas a timeline e os perfís das pessoas no Facebook por outra atividade, de preferência fora da Internet? O prêmio é ser feliz.

Vá ler livro ou uma revista, pode até ser de fofoca, ou mesmo um quadrinho antigo da Turma da Mônica. Aprenda um instrumento musical, ou pratique uma nova música. Aprofunde-se em outro idioma. Veja um filme ou uma série. Tire um cochilo no sofá. Arrume uma gaveta. Separe roupas que você não usa para um bazar beneficente. Imprima as fotos daquela viagem, faça um álbum e convide alguém pra ver. Visite um parente. Cuide de uma planta. Adote um animal. Faça uma caminhada até à padaria e espere a próxima fornada quentinha do pão. Cozinhe uma receita nova. Lave a louça, se estiver afim. Debruce na varanda ou sente-se no banco da praça e veja o vai-e-vem das pessoas. Monte um quebra-cabeça. Faça um artesanato. Faça uma planilha com as finanças. Organize na prateleira os livros que você nunca vai ler por ordem alfabética de autor. Depois reorganize-os por ordem de tamanho, ou cor. Olhe pro teto ou pro chão por horas, imaginando o que fazer caso ganhasse na mega-sena, mesmo que você nunca jogue. Enfim. Só não se perca novamente lá nas redes sociais, colhendo infelicidades gratuitas o tempo todo.

Tá certo que toda tecnologia sofre críticas quando surge, e já sobrevivemos a muitas delas: televisão, telefone, computador pessoal, video-game, celular e a própria Web. Mas algo me sugere que o ócio já foi muito menos nocivo para a nossa psique antes de toda essa hipnose nas redes sociais. Talvez não estejamos preparados para tamanha facilidade de interação social que essas plataformas nos proporcionam. Pensar, discutir e argumentar é saudável. Mas decididamente não precisamos conhecer a opinião de todos sobre tudo o tempo todo, assim como não precisamos formar e emitir opinião sobre tudo o tempo todo. Essa pressão está nos implodindo!

Evitar log de LoginException quando usuário errra senha

Passamos a conviver com um número excessivo de exceções de login do JAAS no Jboss EAP 6.0.1 quando algum usuário errava a senha. Essas exceções não indicam erros do sistema propriamente ditos, e estavam enchendo o log e tornando difícil a análise de outros problemas de produção.

Login failure: javax.security.auth.login.LoginException: Login Failure: all modules ignored
	at javax.security.auth.login.LoginContext.invoke(LoginContext.java:921) [rt.jar:1.6.0_45]
	at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186) [rt.jar:1.6.0_45]
	at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683) [rt.jar:1.6.0_45]
	at java.security.AccessController.doPrivileged(Native Method) [rt.jar:1.6.0_45]
	at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680) [rt.jar:1.6.0_45]
	at javax.security.auth.login.LoginContext.login(LoginContext.java:579) [rt.jar:1.6.0_45]
	...

A opção foi abaixar o nível de log do pacote org.jboss.security para FATAL para todo o Jboss. Isso pode ser feito no standalone.xml seguinte na seção de logging:

<subsystem xmlns="urn:jboss:domain:logging:1.1">
    ...
    <logger category="org.jboss.security">
        <level name="FATAL"/>
    </logger>
    ...
</subsystem>

Kanban

Kanban

Tenho trabalhado num projeto de um kanban simples para tarefas pessoais baseado em JavaScript e HTML5 com local storage. Tenho utilizado no dia a dia para gerenciar minhas tarefas no trabalho, tarefas de casa, além de tarefas relativas ao desenvolvimento do próprio aplicativo. Está sendo útil para mim, e creio que pode ser para outros.

Não busco concorrer com KanbanFlow, Trello e outros kanbans que são online e compartilhados por times. Se trata apenas de um kanban local, armazenado no cache do navegador, para pequenas gestões de pequenas atividades, sem burocracia.

A quem interessar: http://github.com/rafaelodon/kanban

Feedbacks são bem vindos!

Desabilitando a execução do maven-javadoc-plugin herdado do Parent

Aconteceu comigo de vários componentes maven de um projeto herdarem um POM Parent que configura a utilização do Plugin maven-javadoc-plugin. Esse plugin varre todo o código do componente e gera os HTMLs da documentação estilo JavaDoc. No entanto, esse plugin parece demandar muitos recursos para ser executado, onerando o tempo de build. No caso de projetos com muitos componentes, isso pode inclusive significar um tempo muito grande de fila de builds para integração contínua. Para desabilitar a execução do plugin adicionei a entrada project/build/pluginManagement abaixo ao pom.xml dos componentes em questão:

<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  	 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
             http://maven.apache.org/xsd/maven-4.0.0.xsd">

        ...

	<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<artifactId>maven-javadoc-plugin</artifactId>
					<configuration>
						<skip>true</skip>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>

        ...

</project>

Se você desejar ainda desabilitar esse plugin por padrão mas eventualmente gerar o JavaDoc quando for necessário, é possível colocar essa configuração de build acima dentro de um profile do Maven, bastando assim escolhê-lo no momento da execução.