Versionamento de Sistemas, Artefatos e Componentes

Olá pessoal, hoje iremos abordar um assunto voltado para arquitetura de sistemas, onde vamos analisar como realizar um bom versionamento de artefatos e componentes utilizando o Maven.

Os Artefatos

Quando desenvolvemos um sistema Java, iremos ao final gerar algum tipo de artefato para a implantação, seja ele um JAR, WAR, ou EAR.

Ao utilizar o Maven em nossos projetos, temos o chamado GAV no arquivo pom.xml, que são itens obrigatórios para todo tipo de artefato, o GAV é a abreviação de:
  • G (<groupId>): Grupo de trabalho, aqui é um local onde podemos armazenar um grupo artefatos, que fazem parte de um sistema final, exemplo: br.com.cvinicius.erp;
  • A (<artifactId>): Identificação do artefato gerado, este é o nome que terá o artefato, exemplo: erp-web;
  • V (<version>): Versão do artefato, define a versão do artefato gerado, geralmente representado por casas decimais, exemplo: 1.0.0.

O Que é Versionamento

O versionamento é  uma forma de atrelar um conjunto de requisitos, com um nome ou uma numeração, por exemplo:
  • Versão 1.0.0: Login e Cadastro de Clientes;
  • Versão 1.1.0: 1.0 + Relatório de Clientes.
Para definir como será realizado o versionamento, podemos levar em conta vários fatores, o versionamento devem ajudar a equipe na hora de rastrear um bug, implementar uma nova funcionalidade ou criar um novo release de um sistema ou artefato.

Um exemplo que podemos seguir, é o que geralmente é aplicado nos projetos que são alocados nos repositórios do Maven, onde as versões são baseadas em números, como o abaixo:

Versões de um artefato no repositório local do Maven.
No exemplo, temos a representação de um artefato sendo versionado no repositório local do Maven, aqui temos um versionamento com 3 casas decimais, assim podemos rastrear bugs, melhorias e novos releases.

Atrelando Versões com a Gestão de Requisitos

Agora uma pergunta muito importante, como sabemos o que há em cada versão ?

Essa pergunta é um dos pontos mais importantes para que tenhamos um bom versionamento, pois não adianta termos todos os artefatos versionados, mas sem saber quais tarefas foram realizadas em cada versão.

É comum em equipes de desenvolvimento o uso de ferramentas de gestão de requisitos, bug trackers, controle de atividades, etc, vou listar algumas com quais já tive alguma experiência e que podem ser integradas ao nosso padrão de versionamento:


Em cada uma dessas ferramentas temos a distribuição dos projetos, onde cada projeto tem suas versões, atividades, cronogramas, documentação, etc.

Para entender como funciona claramente a integração entre os requisitos com as versões, vamos analisar o exemplo abaixo:

  • ERP
    • 1.0.0 
      • Descrição
        • Módulo de Clientes;
      • Atividades
        • Issue #1;
        • Issue #2;
        • Issue #3;
    • 1.0.1
      • Descrição
        • Correção no Relatório de Clientes
      • Atividades
        • Issue #4;
        • Issue #5;
    • 1.1.0
      • Descrição
        • Módulo de Faturamento;
      • Atividades
        • Issue #6
        • Issue #7;
        • Issue #8.
No exemplo acima temos uma distribuição de um Projeto, Versões e Atividades, agora conseguimos atrelar um código de versão com um artefato.

Qual a vantagem dessa abordagem ?

As vantagens dessa abordagem são muitas, vamos listar algumas delas:
  • Sabemos o que há em cada versão;
  • Controle das atividades realizadas em cada versão;
  • Desenvolvedor responsável por uma determinada alteração;
  • Facilidade de implantação em ambientes de desenvolvimento, homologação e produção.

Repositórios de Artefatos

Um item importante em um bom versionamento, são os repositórios, esses são os locais onde serão armazenados os artefatos, com Maven podemos trabalhar com 2 tipos de repositórios:
  • Local: Esse tipo de repositório é padrão ao se trabalhar com Maven, sempre será criado com base no usuário local da máquina;
  • Global: É um repositório central dentro de uma empresa ou rede, aqui podemos ter um ponto central de armazenamento dos artefatos, assim facilitando uma busca e implantações futuras.

Gerenciadores de Repositórios

Administrar e gerenciar repositórios de artefatos não é uma tarefa fácil, por isso existem várias ferramentas que ajudam nessa missão, um exemplo delas é o Sonatype Nexus.

O Nexus é um gerenciador de artefatos que os centraliza para facilitar a manipulação, gerenciamento, download e reuso dos artefatos, também é importante para armazenar os artefatos das APIs e Frameworks auxiliares que são utilizados nos projetos da empresa, como exemplo: Hibernate e Spring.

Interface principal do Nexus.

Principais funcionalidades do Nexus
  • Centralizar os artefatos fazendo um cache, para servir aos desenvolvedores nas solicitações;
  • Reuso de artefatos, evitando downloads desnecessários e problemas de compatibilidade;
  • Catalogar os componentes e artefatos da empresa.

Ao trabalhar com Gestão de Requisitos + Maven + Versionamento + Repositório Global, temos um melhor gerenciamento do ciclo de vida dos sistemas e componentes da empresa, esse gerenciamento é o ponto de partida para evoluir o ambiente até chegar em recursos mais avançados de Integração e Entrega Contínua.

Até a próxima.

AngularJS - Conhecendo o Framework

Olá pessoal, hoje iremos começar uma série de tutoriais falando sobre o AngularJS, que é um framework JavaScript que veem se tornando muito popular entre os frameworks de front-end.

O  Framework AngularJS

O AngularJS é um framework JavaScript mantido pelo Google para o desenvolvimento de aplicações ricas para Web, sua principal característica é a forma de trabalho, onde suas diretivas estendem os componentes do HTML utilizando marcações. 

Para detalhes sobre o AngularJS podemos visitar o site oficial, onde também encontramos exemplos, links para downloads, cursos, etc.

Site oficial: https://angularjs.org/
Site com tutoriais e exemplos: http://www.w3schools.com/angular/

Começando com AngularJS

Como qualquer outro framework JavaScript, tudo começa com uma importação do arquivo principal do framework:


<!DOCTYPE html>
<html>
  <head>
    <title>Exemplo AngularJS</title>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
  </head>
  <body>
  
  </body>
</html>


Conhecendo as Diretivas

As diretivas do AngularJS, são extensões dos atributos das tags HTML, as diretivas possuem as seguintes caraterísticas:
  • Começam com o prefixo ng-(nome da diretiva);
  • São tags que o AngularJS usa para manipular seus eventos e ações;
  • São colocadas diretamente na tag HTML, por isso que o framework tem o comportamento de extensão do HTML.

Seguindo a normalização do HTML 5, ao invés de usar o prefixo ng-(nome da diretiva) é recomendado usar data-ng-(nome da diretiva).

Vamos agora analisar 3 principais diretivas do AngularJS:
  • data-ng-app: Responsável por inicializar uma aplicação feita com AngularJS, geralmente é adicionada a um elemento pai ma hierarquia de tags do HTML;
  • data-ng-model: Responsável por marcar um ponto de entrada de dados, geralmente aplicada em tags de formulários;
  • data-ng-bind: Utilizada para exibição de dados processados pelo AngularJS.

Exemplo Básico com AngularJS

Agora para mostrar o funcionamento do framework e suas diretivas, vamos montar um exemplo onde entraremos com um dado, e iremos exibi-lo automaticamente na tela:


<!DOCTYPE html>
<html data-ng-app="">
  <head>
    <title>Exemplo AngularJS</title>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
  </head>
  <body>
    <div>
      <p>Digite seu Nome: <input type="text" data-ng-model="nome" /></p>
      <p>Seu nome é: <span data-ng-bind="nome"></span></p>
    </div>
  </body>
</html>

Nos próximos tutorias iremos evoluir os exemplos, utilizando outros comportamentos e diretivas do framework AngularJS.

Download dos exemplos: Conhecendo AngularJS

Até a próxima.

Compressão de CSS e JavaScript utilizando YuiCompressor e Maven

Olá pessoal, hoje iremos abordar um assunto muito interessante que é a compressão de  recursos estáticos de uma aplicação web.

O que são Recursos Estáticos

Em quase todas as aplicações web sempre há os arquivos estáticos, eles são principalmente HTML, CSS e JavaScript, estes tipos de arquivos não mudam seu estado entre as chamadas ao servidor, ou seja, eles são sempre os mesmo independente do número de requests que sejam feitos ao servidor Web.

Antes de detalhar a compressão dos arquivos estáticos, vamos analisar alguns pontos importantes ao importar e utilizar códigos JavaScript e CSS em nossas páginas:
  • Arquivos CSS externos devem ser importados dentro da tag <head>, assim evitamos o problema de flash effect;
  • Arquivos JavaScript externos devem ser importados antes do fechamento da tag <body>, assim não temos problemas no momento da renderização da tela;
  • Sempre que possível agrupe seus arquivos, para evitar várias solicitações ao servidor.
A Compressão de recursos estáticos

A compressão de recursos estáticos é algo muito importante quando queremos aumentar a performance do nosso site ou sistema web, quando adicionamos uma importação de um arquivo externo, seja ele JavaScript ou CSS, é realizado o download desse arquivo para a máquina cliente, esses downloads, podem fazer com que nossa página tenha problemas de lentidão.

Para realizar a compressão dos arquivos, vamos utilizar a ferramenta YUI Compressor, este é muito útil quando queremos comprimir arquivos estáticos.

O YUI Compressor, pode ser usado via linha de comando java, na página onde setamos o código fonte e é realizado a compressão, ou via Maven no momento do build da aplicação.

Utilizando o YUI Compressor com Maven

Vamos criar um projeto Java EE configurado via Maven, contendo 2 arquivos estáticos que serão comprimidos no momento do build:

Projeto Java EE com arquivos estáticos.

Abaixo, temos o conteúdo do arquivo jquery-1.8.3.js, antes de ser comprimido:

Arquivo JavaScript sem compressão.

Abaixo, temos o conteúdo do arquivo jquery-ui-1.10.3.css, antes de ser comprimido:

Arquivo CSS sem compressão.

Abaixo, temos o conteúdo do arquivo index.jsp:

Arquivo JSP que utiliza os arquivos estáticos.

Para que possamos analisar o resultado e eficacia da compressão, iremos testar a aplicação sem executar o plugin do Maven no processo de build, ao solicitar o arquivo index.jsp no browser temos o seguinte resultado:

Resultado da solicitação sem compressão.

Utilizando as ferramentas de desenvolvimento dos navegadores, conseguimos analisar o tamanho de cada arquivo que é solicitado ao servidor, assim temos como saber a quantidade de Bytes que será trafegada em cada solicitação.

Agora para que ao executar o processo de build (criação do artefato .war), sejam gerados os arquivos estáticos comprimidos, vamos adicionar ao arquivo pom.xml do projeto o plugin do yuicompressor:
<build>
  <plugins>
     <plugin>
         <groupid>org.apache.maven.plugins</groupid>
         <artifactid>maven-war-plugin</artifactid>
         <version>2.0.1</version>
         <configuration>
          <warname>${project.artifactId}</warname>
          <webresources>
             <resource>
             <directory>src/main/webapp</directory>
             </resource>
          </webresources>
         </configuration>
     </plugin>
     <plugin>
         <groupid>net.alchim31.maven</groupid>
         <artifactid>yuicompressor-maven-plugin</artifactid>
         <version>1.4.0</version>
         <executions>
           <execution>
            <phase>package</phase>
             <goals>
               <goal>compress</goal>
             </goals>
           </execution>
         </executions>        
     </plugin>
  </plugins>
</build> 

A estrutura criada após executar o build utilizando o plugin yuicompressor, é a seguinte:
Estrutura do arquivo .war após o build com yuicompressor.

Agora temos o seguinte resultado ao executar o arquivo index.jsp, este foi alterado para utilizar os arquivos comprimidos jquery-ui-1.10.3.min.css e jquery-1.8.3-min.js.

Resultado da solicitação com compressão.

Com este resultado, conseguimos notar a importância de realizar a compressão de arquivos estáticos em aplicativos web, a compressão aliada a outras formas otimizações, podem contribuir para a melhora da performance das aplicações web.

Até a próxima.

Replicação de sessão com VRaptor 3.5 e Cluster de Tomcat 7

Olá pessoal, hoje vou mostrar detalhes de uma aplicação desenvolvida com VRaptor rodando em um cluster de Tomcat 7.

Características da Aplicação

A aplicação foi desenvolvida utilizando:
  • JDK 6;
  • VRaptor 3.5.3;
    • Spring 3.0.5, como provider de IoC/DI;
  • Banco de dados PostgreSQL.
Características do Ambiente

O ambiente foi projetado com: 
  • Apache Web Server 2.2.22;
    • Sendo responsável pelo balanceamento de carga;
  • Tomcat 7.0.54;
    • JVM versão 6;
    • Sendo este um cluster de 2 nós.
Regras para replicação de sessão em Java EE

Para que possamos trabalhar com cluster em um ambiente Java EE, a aplicação deve seguir algumas regras, que são as seguintes:
  • A aplicação deve ter a tag <distributable /> no deployment descriptor;
  • Todos os dados que serão replicados, devem implementar a interface java.io.Serializable;
  • Para armazenar ou alterar um objeto na sessão, sempre devemos invocar o método setAttribute
Seguindo estas regras, podemos afirmar que aplicação pode funcionar em um ambiente de cluster.

O VRaptor

O VRaptor é um framework utilizado para o desenvolvimento de aplicações web, os principais recursos que o tornam uma ótima escolha para a camada Web Tier são as seguintes:
  • Baseado em REST;
  • Fácil integração com outros frameworks como Spring, Tiles, Velocity, etc;
  • Suporte e documentação;
  • Fácil geração e manipulação de XML e JSON;
  • Possibilidade de troca do provider de IoC/DI.
Observação: Neste tutorial estamos usando a versão 3.5.3 do VRaptor, que utiliza o Google Guice como provider padrão para IoC, atualmente o VRaptor encontra-se na versão 4.0.0, onde seu core foi reescrito e padronizado para utilizar CDI (Context Dependecy Injection), para mais detalhes acesse o site oficial do framework

Tratamento de objetos com @SessionScoped

Em quase todas aplicações web trabalhamos com dados na sessão, seja ele para autenticar um usuário, ou para manter estado em chamadas ao servidor, com VRaptor, podemos marcar uma classe para que tenha seu estado armazenado na sessão, isso acontece com a anotação @SessionScoped.

O Problema

Um dos grandes problemas quando trabalhamos em ambientes clusterizados é a replicação de sessão, quando uma sessão tem seus dados alterados, o contêiner deve replicar esta alteração entre os nós do cluster, assim garantindo a confiabilidade do sistema.

Em nosso exemplo, utilizei o Spring como provider de IoC/DI, assim ele será o responsável por gerenciar a criação e manipulação dos objetos do VRaptor.

Ao realizar o deployment da aplicação tudo acontece normalmente, mas notamos, que ao alterar um objeto marcado como @SessionScoped a alteração mesmo não é replicada entre os nós do cluster.

A Solução 

Para encontrar um solução para o problema, foram executado uma bateria de testes no sistema, para que o motivo dessa falha fosse descoberto, segue os testes:

  • Realizar alteração na sessão invocando diretamente o método setAttribute da classe HttpSession;
  • Manipulação dos listeners HttpSessionAttributeListener, HttpSessionBindingListener e HttpSessionActivationListener pertencentes ao pacote javax.servelet.http.*, com eles seria possível monitorar as alterações nos atributos da sessão e também a migração entre JVMs;
  • Trocar o Spring pelo Google Guice, como do provider de IoC/DI do VRaptor.
Ao realizar o ultimo teste, tivemos um resultado positivo, pois os objetos marcados como @SessionScoped foram replicados entre os nós do cluster, garantindo assim a confiabilidade do sistema.

Para utilizar o Google Guice como provider é muito simples, porque como mencionei acima, ele é o provider padrão utilizado pelo VRaptor 3.5.

Referências sobre as tecnologias utilizadas:

Até a próxima.

Maven 3 com Java EE - ClassFormatError: Absent Code attribute in method that is not native or abstract in class file

Olá pessoal, hoje iremos aprender a solucionar um erro estranho que acontece quando trabalhamos com projetos Maven e Java EE.

Especificação Java EE

Como já sabemos, no Java EE tudo segue uma especificação, e cada uma delas possui uma identificação que é chamada de JSR (Java Specification Requests), elas possuem implementações de diferentes fornecedores, um exemplo disso é a JPA (Java Persistence API), que é uma especificação para mapeamento e persistência de objetos relacionais, ela possui várias implementações diferentes, entre elas estão: Hibernate, TopLink, EclipseLink, etc.

Maven e Projetos Java EE

Como vimos nos outros tutoriais sobre o Maven, o desenvolvimento e as configurações do projeto ficam muito simples quando o utilizamos, com Maven podemos setar várias configurações diferentes como: versão de compilação, dependências, plugin para automatizar processos, etc.

Dependência do Java EE

Em um projeto Java EE geralmente trabalhamos com várias especificações, um bom exemplo seria um projeto web dividido em 3 camadas diferentes: Web Tier (JSP, Servlets, JSF), Business Tier (CDI, EJB) e Integration Tier (JPA), para este cenário, podemos setar uma única dependência nas configurações do Maven:


Esta dependência esta localizada no repositório do java.net, ela é apenas composta pela especificação, e não possui nenhuma implementação, nem mesmo corpo nos métodos das APIs.

Exception: ClassFormatError: Absent Code attribute in method that is not native or abstract in class file

Ao tentar executar um teste com algum framework de testes unitários ou até mesmo um método main em nosso projeto, recebemos este erro estranho, ele diz basicamente que a classe esta incompleta e não pode ser utilizada em ambiente de execução. 

Isto acontece, porque a dependência do repositório java.net, é para ser utilizada somente em tempo de compilação, por não ter implementações e nem corpo nos métodos.

Para mais detalhes sobre a exception java.lang.ClassFormatError, consulte o javadoc da classe: http://docs.oracle.com/javase/6/docs/api/java/lang/ClassFormatError.html.

Solução

A solução para este erro  é trocar a dependência para uma completa, neste caso optei pela dependência localizada no repositório da JBoss


Também podemos tratar este erro de maneira mais simples, imagine que em nosso projeto queremos testar apenas o envio de e-mails com a API JavaMail, para isso, não precisamos de toda a infraestrutura do Java EE, basta adicionar a dependência desejada no pom.xml e manter a dependência do java.net, assim a execução acontecerá normalmente:

Até a próxima.