Thursday, November 16, 2017

Adicionando Opções de Resolução de Tela no Linux

O camando xrandr é um utilitário de configuração do X Window, framework básico para construção de diversos padrões de interfaces gráficas no estilo desktop. O xrandr permite a (re)configuração do X Window dinamicamente, isto é, sem necessidade de reiniciar o servidor. Você também pode obter informações técnicas sobre o monitor e o ambiente gráfico em geral tais como resolução, refresh rate, etc.

Execute camando xandr sem parâmetros e veja todos os outputs (geralmente monitores) conectados ao sistema e alguns detalhes técnicos de cada, como as resoluções:
~ $ xrandr
Screen 0: minimum 8 x 8, current 1680 x 1050, maximum 32767 x 32767
VGA1 connected 1680x1050+0+0 (normal left inverted right x axis y axis) 477mm x 268mm
   1680x1050     59.95*+  
   1280x1024     75.02    60.02  
   1152x864      75.00  
   1024x768      75.03    60.00  
   800x600       75.00    60.32  
   640x480       75.00    59.94  
   720x400       70.08  
VIRTUAL1 disconnected (normal left inverted right x axis y axis)
A saída do comando mostra um VGA1 conectado e a resolução marcada com * e + indicam a que está sendo usada no momento e a preferencial, respectivamente.
Com essas informações, você pode definir uma opção de resolução diferente para o monitor (desde que ela esteja disponível). Por exemplo você pode adicionar a resolução 1920x1080 com o seguinte comando:
~ $ cvt 1920 1080
# 1920x1080 59.96 Hz (CVT 2.07M9) hsync: 67.16 kHz; pclk: 173.00 MHz
Modeline "1920x1080_60.00"  173.00  1920 2048 2248 2576  1080 1083 1088 1120 -hsync +vsync

Repare em todo trecho que vem após modeline. Copie-o e cole como parâmetro para o comando xrandr:
$ xrandr --newmode "1920x1080_60.00"  118.25  1600 1696 1856 2112  900 903 908 934 -hsync +vsync

Em seguida, execute novamente:
~ $ xrandr --addmode VGA1 "1920x1080_60.00"

A partir deste ponto a nova resolução 1920x1080 já estará disponível em suas configurações de monitor. Caso seu desktop seja um XFCE, por exemplo, você poderá encontrar a nova opção em settings/display a partir do menu inicial, como a janela abaixo:



Wednesday, November 1, 2017

Desenvolvimento JavaEE: CDI, JPA, JSF, JTA, WildFly e Maven: parte 2

Criando uma aplicação Java para acessar o DataSource



Dando sequência à parte 1 deste artigo onde configuramos o datasource no servidor WildFly 10, agora criamos a aplicação.
Abra o Eclipse e crie um Novo Projeto Maven (File/New/Other.../Maven Project). Marque a opção Create a Simple Project e Next:



Informe as propriedades do projeto e na combobox Packaging escolha war. Finish:


Vá em propriedades do projeto. No painel esquerdo selecione Project Facets. No painel direito marque as opções CDI, JPA e Java Server Faces. Mais à direita, na aba Runtimes marque WildFly. Clique em Apply e OK:



No arquivo pom.xml adicionamos as dependências do JPA (hibernate):

<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">
 <modelVersion>4.0.0</modelVersion>
 <groupId>TestDataSource</groupId>
 <artifactId>TestDataSource</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>war</packaging>
 <dependencies>
  <dependency>
   <groupId>org.jboss.logging</groupId>
   <artifactId>jboss-logging</artifactId>
   <version>3.3.1.Final</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-lang3</artifactId>
   <version>3.6</version>
  </dependency>
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-validator</artifactId>
   <version>6.0.2.Final</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-core</artifactId>
   <version>5.2.10.Final</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-entitymanager</artifactId>
   <version>5.2.10.Final</version>
   <scope>provided</scope>
  </dependency>
  <dependency>
   <groupId>com.lowagie</groupId>
   <artifactId>itext</artifactId>
   <version>2.1.7</version>
   <scope>compile</scope>
  </dependency>
 </dependencies>
</project>

Na pasta META-INF o eclipse já cria para nós o arquivo persistence.xml dentro do qual informamos alguns parâmetros do JPA, como o nome do data source no servidor, instruímos a gerar tabelas no banco de dados a partir das classes do projeto e mostrar os scripts SQL por exemplo.

persistence.xml
<?xml version="1.0" encoding="UTF-8"?>

<persistence version="2.1"
 xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

 <persistence-unit name="TestDataSource">
  <provider>org.hibernate.ejb.HibernatePersistence</provider>
  <jta-data-source>java:jboss/datasources/empresaDB_DS_mysql</jta-data-source>

  <properties>
   <property name="javax.persistence.schema-generation.database.action"
    value="none" />
   <property name="hibernate.format_sql" value="true" />
   <property name="hibernate.show_sql" value="true" />
   <property name="hibernate.hbm2ddl.auto" value="update" />
  </properties>
 </persistence-unit>
</persistence>


Entidade Funcionario

Agora que o projeto já está configurado, crie  pacote chamado entidades e nele a classe Funcionario como segue. A anotação @Entity informa ao JPA que essa classe será uma tabela no banco de dados:
@Entity
public class Funcionario implements Serializable{

 @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id; //chave primaria da tabela 
 
 private String nome;

 private Integer idade;

 private Date nascimento;

 private Double salario;
 
 //getters, setters omitidos para clareza
}

Até o momento a estrutura do nosso projeto está como na imagem:



Página JSF e Managed Bean

Crie um pacote chamado controle e nele a classe chamada FuncionarioMB e FuncionarioService, onde esta é responsável por intermediar as ações com o banco de dados (salvar, editar, excluir, etc) e aquela gerencia os eventos na interface gráfica com o usuário, neste caso a página web:

FuncionarioMB (gerencia os eventos na web page):
import java.util.List;
import javax.inject.Inject;
import javax.enterprise.inject.Model;
import javax.transaction.Transactional;
import entidade.Funcionario;

@Model
public class FuncionarioMB {

 @Inject
 private FuncionarioService funcionarioService; 
 
 private Funcionario funcionario = new Funcionario();
 private List<Funcionario> funcionarios;  
 
 //diz para o servidor wildFly abrir transação para persistir objeto no banco
 //o próprio servidor faz o commit após o método retornar
 @Transactional 
 public String salvar() {  
  funcionarioService.salvar(funcionario);
  return null;
 }
 
 public Funcionario getFuncionario() {

  return funcionario;
 }

 public void setFuncionario(Funcionario funcionario) {
  this.funcionario = funcionario;
 }

 public List<Funcionario> getFuncionarios() {
  
  //busca todos os registros na tabela e exibe
  if(funcionarios == null)
   funcionarios = funcionarioService.buscarTodos();
  
  return funcionarios;
 }
}

FuncionarioService (camada de serviço e acesso ao banco de dados):

package controle;

import java.util.List;
import javax.enterprise.inject.Model;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import entidade.Funcionario;

@Model
public class FuncionarioService {

 @PersistenceContext
 private EntityManager entityManager;
 
 public void salvar(Funcionario funcionario) {

  entityManager.persist(funcionario);  
 }
 
 public List<Funcionario> buscarTodos() {

  String query = "SELECT f FROM Funcionario f";
  return entityManager.createQuery(query).getResultList();
 }
}

Agora podemos criar a web page. No diretório src/main/webapp crie a pasta index.xhtml:
<!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"
 xmlns:ui="http://java.sun.com/jsf/facelets"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:h="http://java.sun.com/jsf/html">

 <h:body>
 <h:form>
  <h:outputText value="Cadastro de Funcionário" />
  <h:panelGrid columns="2">
   <h:outputText value="Nome" />
   <h:inputText value="#{funcionarioMB.funcionario.nome}" />
   <h:outputText value="Idade" />
   <h:inputText value="#{funcionarioMB.funcionario.idade}" />       
   <h:outputText value="Salário" />
   <h:inputText value="#{funcionarioMB.funcionario.salario}" >
    <f:convertNumber pattern="#0.00" locale="pt"/>
   </h:inputText>
   <h:outputText value="Data Nascimento" />
   <h:inputText value="#{funcionarioMB.funcionario.nascimento}" >
    <f:convertDateTime pattern="dd/MM/yyyy" locale="pt" />
   </h:inputText>
   <h:commandButton action="#{funcionarioMB.salvar()}" value="Salvar" />
  </h:panelGrid>
  <p/>
  Lista
  <h:dataTable value="#{funcionarioMB.funcionarios}" var="funcionario" border="1">
   <h:column>
    <h:outputText value="#{funcionario.nome}" />
   </h:column>
   <h:column>
    <h:outputText value="#{funcionario.idade}" />
   </h:column>
   <h:column>
    <h:outputText value="#{funcionario.salario}" >
     <f:convertNumber pattern="#0.00" currencySymbol="$" locale="pt"/>
    </h:outputText>
   </h:column>
   <h:column>
    <h:outputText value="#{funcionario.nascimento}" >
     <f:convertDateTime pattern="dd/MM/yyyy" locale="pt" />
    </h:outputText>
   </h:column>
  </h:dataTable>
 </h:form>
 </h:body>
</html>
Todo input de texto em aplicações web são interpretados por padrão como texto puro, dessa forma utilizamos alguns converters padrão do JSF para a adpatar os tipos de dados que não são texto, como a idade, nascimento, e salário.
Pronto. A aplicação já está pronta para rodar. Clique com o botão direito na pasta raíz da aplicação, escolha Run as, em seguida Run on Server. A aplicação será acessada na porta default do servidor, geralmente a 8080:


Insira registros válidos (como nenhuma regra de validação foi implementada, se você inserir registros inválido, a aplicação vai lançar um erro) e salve. A tabela lista os funcionário cadastrados até o momento.
A estrutura final do projeto ficou como segue:


Confira também!
Relatórios em Java para Iniciantes



Wednesday, October 18, 2017

Desenvolvimento JavaEE: CDI, JPA, JSF, JTA, WildFly e Maven: parte 1

Aplicações Java Enterprise acessam banco de dados utilizando a API JDBC. Nela os bancos de dados são acessados usando objetos do tipo DataSource, os quais possuem uma série de propriedades que identificam o banco de dados real como a URL do servidor, o nome do banco de dados, senha, etc.

Antes de acessar o banco de dados, a aplicação precisa criar uma conexão, e um objeto DataSource funciona como um factory de conexões entre o banco e a aplicação. Quando o DataSource é gerenciado pelo servidor de aplicações, geralmente a ele é associado um JNDI, que é um nome para o datasource. Assim quando a aplicação demanda uma conexão, ela utiliza o JNDI, o servidor instancia o(s) objeto(s) DataSource e disponibilizam a conexão.

Datasources em servidores Java EE geralmente implementam o poolingque são algoritmos de instanciação de DataSources totalmente transparentes à aplicação os quais otimizam a liberação, abertura e fechamento de conexões com o banco de dados.

DataSources para o banco de dados MySQL no servidor WildFly 10



Faça download da API JDBC do MySQL (mysql-connector-java-5.1.21.jar) e, caso necessário, baixe também o servidor WildFly 10 Java EE7 Full & Web Distribution . No MySQL, crie um banco de dados chamado EmpresaBD.

No WildFly, DataSources também são chamados de módulos. Assim, para acessar o MySQL do servidor precisamos instalar um novo módulo para ele. No diretório raiz do WildFly, há a pasta modules. A partir dela crie os diretórios /com/mysql/main/ da forma que segue:

WILDFLY_HOME/modules/com/mysql/main/

Dentro da pasta main cole o driver do MySQL que você acabou de baixar e crie um arquivo chamado module.xml, o qual conterá a definição do módulo cujo nome é com.mysql. 

A variável JBOSS_HOME aponta para pasta module e os arquivos e pastas criados lá dentro serão usados para carregar o datasource quando o servidor iniciar. O conteúdo do arquivo module.xml deve ser como segue:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="com.mysql"> 
    <resources>
        <resource-root path="mysql-connector-java-5.1.21.jar"/>
    </resources>
    <dependencies>
        <module name="javax.api"/>
        <module name="javax.transaction.api"/>
    </dependencies>
</module>

Salve e feche o arquivo module.xml. A estrutura de diretórios que criamos então fica dessa forma:
  • WILDFLY_HOME/modules/com/mysql/main/mysql-connector-java-5.1.21.jar
  • WILDFLY_HOME/modules/com/mysql/main/module.xml

O módulo que permite acessar o MySQL do WildFly está instalado. Agora só precisamos criar o data source para o banco EmpresaDB. Para isso temos que editar o arquivo standalone.xml passando as coordenadas do banco (usuário, senha, etc.). Esse arquivo está localizado em:
  • WILDFLY_HOME/standalone/configuration/standalone.xml 
Abra esse arquivo, localize a tag <dataSources> e dentro dela cole o seguinte trecho (ajustando usuário e senha de acordo com suas configurações pessoais):
<datasource jta="true" jndi-name="java:jboss/datasources/empresaDB_DS_mysql"
 pool-name="empresaDB_DS_mysql" enabled="true">

 <connection-url>jdbc:mysql://localhost:3306/EmpresaDB</connection-url>
 <driver-class>com.mysql.jdbc.Driver</driver-class>
 <driver>mysql</driver>
 <security>
  <user-name>root</user-name>
  <password>P@ssword1</password>
 </security>

</datasource>

Ainda dentro da tag <dataSources> localize a tag <drivers> e dentro dela cole este trecho:
<driver name="mysql" module="com.mysql"/>
Repare que a tag driver aponta para o módulo que criamos. E o datasource que criamos aponta para a esta tag driver cujo nome é mysql.

Salve e feche o arquivo standalone.xml. Pronto. Inicie o servidor WildFly executando o arquivo standalone.sh (para Linux) ou standalone.bat (para Windows) localizado em WILDFLY_HOME/bin/

Acesse o console do servidor na porta 9990. Clique na aba Configurations, depois vá clicando em Subsystems, DataSources, Non-XA. Localize o datasource criado EmpresaDB_DS_mysql e teste a conexão. Conforme a imagem:



Repare que o nome que registramos, empresaDB_DS_mysql, é o que será usado na aplicação para que ela solicite ao servidor uma conexão com o banco de dados EmpresaDB.

Na parte 2 deste artigo criamos uma aplicação JavaEE que acessa o DataSource.

Confira também!
Relatórios em Java para Iniciantes




Referências:
ĆMIL , Michal; MATLOKA, Michal ; MARCHIONI, Francesco . Java EE 7 Development with WildFly. 2. ed. Birmingham: Packt Publishing Ltd., 2013
       

Access restriction: The type 'Application' is not API (restriction on required library '/usr/lib/jvm/jdk1.8.0_144/jre/lib/ext/jfxrt.jar')

Recentemente ao criar um projeto JavaFX no Eclipse, a IDE disparava uma advertência sempre que eu tentava importar algo do pacote javafx.*


Para corrigir isso, vá em propriedades do projeto. Na janela que abrir selecione Java Build Path, vá na tab libraries e expanda o item JRE System Library, conforme a imagem:


Selecione o item Access Rule e depois o botão Edit.... Na janela que abrir clique no botão Add... .Na caixa de texto Rule Pattern coloque javafx/** e na combo box Resolution escolha a opção Accessible Conforme a imagem:


Clique em OK, Apply e OK. Limpe e construa seu projeto novamente. As advertências deixam de aparecer.



Monday, October 16, 2017

Generic Lazy Loading com JSF e PrimeFaces

Lazy Loading é um padrão de projeto que atrasa o carregamento de dados na memória até o momento quando eles são estritamente necessários. Em sistemas orientados a objeto, as entidades estão sempre relacionadas umas com as outras de modo que esses níveis de relacionamento podem se extender indefinidamente dependendo do tamanho do sistema. Se a aplicação não implementa uma estratégia adequada para listar os registros em uma tabela, ela corre o risco de carregar uma quantidade absurda de dados na mémória sem necessidade, o que pode prejudicar seu desempenho.

O componente p:dataTable do framework PrimeFaces permite implementar LazyLoading de forma muito simples bastando que o desenvolvedor estenda LazyDataModel<T>, onde T é o tipo da entidade que será carregada na tabela. Por exemplo, suponha que você tenha uma entidade Pessoa, você deveria extender LazyDataModel da seguinte forma:
public class LazyTablePessoa extends LazyDataModel<Pessoa>{

   private PessoaService service;

   @Override
   public List<Pessoa> load(int first, int pageSize, String sortField, 
                               SortOrder sortOrder, Map<String, Object> filters) {

     
        List<Pessoa>listPessoa = pessoaService.getPessoas(first, first + pageSize);
        int linhas = pessoasService.countPessoas();
        setRowCount(linhas);
        return listPessoa;
    }
  //... outros métodos
}
Essa abordagem possui um problema se o projeto for crescendo e um número cada vez maior de entidades demandar lazy loading em determinadas telas. Dessa forma seria necessário implementar  LazyDataModel para cada entidade que você queira exibir. Se houver 100 entidades para listar, você terá que implementar 100 extensões de LazyDataModel, cada uma com o código praticamente idêntico!

Generic Lazy Data Table
Somente os dados exibidos são carregados na memória.

Podemos reduzir drasticamente essa quantidade de implementações criando uma única extensão genérica de LazyDataModel que atenda, digamos, 90% de todas as necessidades de exibição, ou seja, você podera ter 100 entidades no seu modelo, mas uma única implementação de LazyDataModel será suficiente para listar as entidade de acordo com o padrão lazing.

Para implementar este padrão precisamos criar:
  1. Uma DataTable genérica que extenda LazyDataModel
  2. Uma interface de serviço genérica que busque os dados. As especificações de busca para cada entidade variam de acordo com a implementação.
O diagrama de classes abaixo resume o modelo:


Implementando o diagrama

Pessoa.java
public class Pessoa {
    
    private String nome;
    private int idade;
    private Date nascimento;

    //métodos getters & setters
}

GenericService.java
public interface GenericService<T> {
    //a quantidade de registros que serão carregados
    List<T> buscaPaginada(int inicio, int fim);
    //a quantidade de registros na fonte de dados
    int countLinhas();
}
PessoaService
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class PessoaService implements GenericService<Pessoa>{

    //representando o banco de dados
    private List<Pessoa> dataSource;
    
    public PessoaService() {

        dataSource = new ArrayList<>();
        for(int i = 0; i < 100; i++){
            Pessoa p = new Pessoa();
            p.setNome("Pessoa "+i);
            p.setIdade(i);
            p.setNascimento(new Date());
            dataSource.add(p);
        }        
    }    

    //implementação para a entidade pessoa
    //as regras podem variar de entidade para entidade...
    @Override
    public List<Pessoa> buscaPaginada(int inicio, int fim) {        

        return dataSource.subList(inicio, fim);
    }

    @Override
    public int countLinhas() {

        return dataSource.size();
    }    
}

Nossa implementação de GenericLazyDataTable. Repare que o tipo do objeto é genérico (T), ou seja, a princípio não se sabe qual é o tipo de objeto sendo buscado nem qual é o critério de busca, que
dependerá da implementação fornecida para a interface GenericService.

import java.util.List;
import java.util.Map;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.SortOrder;

public class GenericLazyDataTable<T> extends LazyDataModel<T>{
        
    private final GenericService genericService;

    public GenericLazyDataTable(GenericService genericService) {

        this.genericService = genericService;
    }

    @Override
    public List<T> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {

        int linhas = genericService.countLinhas();
        this.setRowCount(linhas);
        return genericService.buscaPaginada(first, first + pageSize);
    }    
}

O managed bean controller da página JSF
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

@Named
@ViewScoped
public class ManagedBean implements Serializable{
    
    private GenericLazyDataTable genericLazyDataTable;
    private GenericService genericService;    

    @PostConstruct
    public void init(){        

        genericService = new PessoaService();
        genericLazyDataTable = new GenericLazyDataTable(genericService);
    }

    public GenericLazyDataTable getGenericLazyDataTable() {

        return genericLazyDataTable;
    }        
}

E a página inicial index.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!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"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:p="http://primefaces.org/ui"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>Lazy Pessoa</title>
    </h:head>

    <h:body>
        <p:dataTable value="#{managedBean.genericLazyDataTable}" var="pessoa" lazy="true" rows="20" paginator="true">

            <p:column headerText="nome">
                <h:outputText value="#{pessoa.nome}" />
            </p:column>

            <p:column headerText="idade">
                <h:outputText value="#{pessoa.idade}" />
            </p:column>

            <p:column headerText="nascimento">
                <h:outputText value="#{pessoa.nascimento}" >
                    <f:convertDateTime pattern="dd/MM/yyyy" locale="pt" />
                </h:outputText>
            </p:column>

        </p:dataTable>
    </h:body>
</html>

Estrutura do projeto na IDE NetBeans 8.1 (utilizando Maven)


Tornando a implementação ainda mais genérica

É possível tornar esse modelo ainda mais genérico. Por exemplo poderíamos criar um campo Map em GenericLazyDataTable e sobrecarregar o método buscaPaginada de GenericService para definir filtros de busca. Algo como: 
private Map<String, Object> filtrosPersonalizados;

//outros campos...

//pode ser chamado pelo Managed Bean
public void adicionarFiltro(String nomeDocampo, Object tipoDoCampo) {

        filtrosPersonalizados.put(campo, object);
}

Friday, July 28, 2017

Atualizando a variável JAVA_HOME no Linux

JAVA_HOME é uma variável de ambiente que aponta um diretório JDK no seu sistema. Essa variável é utilizada como referência por vários aplicativos que usam o java para rodar. Se ela não existir ou estiver incorretamente configurada, muitos aplicativos podem não executar.

O arquivo home/.bashr contém o script the execução além de vários parâmetros para iniciar o shell bash, que é a versão mais comum em Linux para terminais de linhas de comando. Para atualizar a JAVA_HOME anexamos o camando export no final do arquivo .bashr junto com o novo valor da variável.

Suponha que você baixou a última versão do JDK, que hoje é jdk1.8.0_141, no diretório:

/usr/lib/jvm/jdk1.8.0_141/

Utilizando o editor de texto vi, abra o arquivo .bashr
vi .bashr
Adicione no final do arquivo os camandos:

export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_141/
export PATH=$JAVA_HOME/bin:$PATH

No final do arquivo adicionamos o novo valor de JAVA_HOME e exportamos para o PATH
Variáveis de ambiente e de shell são definidas através do comando export. A última linha adiciona a variável JAVA_HOME na variável PATH, a qual mapeia todos os comandos reconhecidos pelo terminal shell bash.

Observação: o editor de texto vi funciona em dois modos, comando e inserção, caso você tenha alguma dificuldade, dê uma olhada aqui. Ou você também pode utilizar outro editor de texto, como o nano por exemplo.

Salve e feche o arquivo. Efetive as mudanças que você acabou de realizar no arquivo .bash utilizando o camando source:
source ~/.bashrc
Pronto! Agora imprima o valor de JAVA_HOME. A saída deve ser semelhante à do comando  java -version:
$ echo $JAVA_HOME
/usr/lib/jvm/jdk1.8.0_141
$ java -version
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, mixed mode)
Seu java está atualizado.

Wednesday, July 5, 2017

Adding Commands to Linux PATH

If you know in which directory the command you want execute is, just type the path until .sh file and run it. This might be boring if the path is too long though. A more effective way is creating a script containing the whole command and add it to the environment variable PATH.

In order to know which directories are mapped by the PATH, run:
echo $PATH
A possible output is this:
/home/rafael/bin:/home/rafael/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8 oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin
The mapped directories are split by two points. Some directories are mapped by default. As you can see ~/bin (/home/rafael/bin) is one of these. This means that if we add some scripts in ~/bin, we will be able to run those scripts from anywhere by just prompting the file script name.

Example: Running Wildfly10 server through the PATH

Assuming your Wildfly server is located at /usr/share/wildfly-10.1.0.Final, let's add to PATH two commands, one to start the server and other to start the server client interface whose full path is /usr/share/wildfly-10.1.0.Final/bin/jboss-cli.sh.

We are just going to create one file called wildfly10 (touch wildfly10) to start the server and other called wildfly_cli (touch wildfly_cli) to run the client, each one containing the respective scripts (echo "..."). After that we give permission (chmod 755...) to make these files executable and that's all.

Starting from your home directory, type:
cd bin
touch wildfly10
echo "sudo /usr/share/wildfly-10.1.0.Final/bin/standalone.sh" > wildfly10
chmod 755 wildfly10
touch wildfly10_cli
echo "sudo /usr/share/wildfly-10.1.0.Final/bin/jboss-cli.sh" > wildfly10_cli
chmod 755 wildfly10_cli
Ready! Wildfly command is on your PATH. Let's try it:

First we start the server by prompting wildfly10

And now running the client server:

Prompting wildfly_cli from anywhere we start the client

And accessing server http port:

localhost:9990

You can add any commands you want to the PATH!


Tuesday, July 4, 2017

Casos de Mapeamento de Coleções no JPA

Aplicações corporativas são essencialmente definidas por sua necessidade de colher, tranformar e exibir uma quantidade enorme de informações. Java Persistence API (JPA) é o framework padrão de aplicações java para fazer a ponte entre o domínio orientado a objetos e o modelo relacional de banco de dados.

Coleções do tipo Collection, List, Set, Map são umas das estruturas de dados mais utilizadas e o JPA permite seu mapeamento para o modelo relacional  de forma simples e eficiente. Você só precisa utilizar as anotações adequadas e não se preocupar como as coleções estão sendo representadas no banco de dados! Vejamos os casos mais comuns de mapeamento de coleções, sejam as coleções classes de entidade, classes embutidas ou tipos básicos:

  • Multiplicidade simples entre uma classe de entidade e classes não-entidade (classes embutidadas)
Exemplo: Uma empresa pode ter muitos endereços (Endereço aqui é uma classe embutida):
@Embeddable
class Endereco{}

@Entity
class Empresa{

   @ElementCollection
   Set<Endereco> enderecos; 

//para classes embutidas, utilize @ElementCollection.
}
Opcionalmente você pode especificar como o JPA deve gerar a tabela de coleções no banco de dados fornecendo alguns parâmetros:
@Entity
class Empresa{

   @Id int idEmpresa;

   @ElementCollection
   @CollectionTable(name="logradouro", joinColumns=@JoinColumn(name="emp_id"))
   @AttributeOverride(name="address", column=@Column(name="o_nome_q_vc_quiser"))
   Collection<Endereco> enderecos;
}
No exemplo anterior, para representar a coleção de endereços da empresa, dissemos para o JPA criar uma tabela chamada logradouro. @JoinColumn representa a chave estrangeira.

Usar a anotação @ElementCollection é o mínimo que você precisa fazer para mapear a maioria dos tipos de coleções. Nos próximos exemplos vamos explorar coleções mais sofisticadas utilizando índices.


Multiplicidade indexada (pares chave/valor)


Pares chave/valor são representados pela interface Map. Coleções desse tipo são muito comuns e são utilizadas em praticamente todas as aplicações. O JPA é bastante flexível com tipos Map. As entidades ou classes embutidas podem representar tanto a chave quanto o valor, ou ainda chave e valor podem ser tipos primitivos.

1 Chave e Valor são tipos primitivos


Exemplo: Um funcionário pode ter vários números de telefone e cada número é de um tipo (comercial, trabalho, casa, etc.):

Essencialmente você só precisa da usar a anotação @ElementCollection para resolver seu problema. Todas as outras são opcionais.
@Entity
public class Funcionario{

   @Id private int id;

   @ElementCollection
   @CollectionTable(name="funcionario_telefone") //opcional, define o nome da tabela no banco
   @MapKeyColumn(name="tipo_telefone") ///opcional indica qual coluna armazena achave
   @Column(name="numero") //nome da coluna que armazena o valor
   private Map<String, String> telefones;
   //...
}
2 A chave do Map pode ser uma enum ou uma data
Constantes enumeradas dão mais consistência e legibilidade ao código. Como no exemplo anterior, mas ao invés de usarmos um tipo básico como chave, usamos uma enum. Novamente a única anotação obrigatória é @ElementCollection, mas podemos definir como o valor da enumeration será armazenado no banco de dados, se sob a forma literal ou numérica, assim precisamos utilizar a anotação @MapKeyEnumerated
public enum TipoTelefone {HOME, MOBILE, WORK}

@Entity
public class Funcionario{

   @Id private int id;

   @ElementCollection
   @CollectionTable(name="funcionario_telefone") //opcional, define o nome da tabela no banco
   @MapKeyEnumerated(EnumType.STRING)
   @MapKeyColumn(name="tipo_telefone") ///opcional indica qual coluna armazena a chave
   @Column(name="numero") //nome da coluna que armazena o valor
   private Map<TipoTelefone, String> telefones;
   //...   
}
Caso quisessemos usar como chave o tipo java.util.Date, poderíamos usar a anotação @MapKeyTemporal ao invés de @MapKeyEnumerated.

3 Chave é um tipo básico e valor é uma entidade
Exemplo: Um departamento tem vários cubículos cada qual com um funcionário.
A modelagem tradicional um departamento tem muitos funcionários ainda não atenderia eficazmente esse cenário. O software precisa indexar cubículo e funcionário.
@Entity
public class Departamento{

   @Id private int id;

   @ManyToMany
   @JoinTable(name="DEPT_EMP", joinColumns=@JoinColumn(name="DEPT_ID"),
                    inverseJoinColumn=@JoinColumn(name="EMP_ID"))
                    @MapKeyColumn(name="CUB_ID")
   private Map<String, Funcionario> funcionarioPorCubiculo;
}
4 Chave é o ID da própria entidade que representa o valor do Map
É comum e intuitivo indexar a chave do map pelo ID da entidade. No exemplo anterior o poderíamos usar algum atributo do funcionário como identificador do cubículo ao invés do próprio nome atribuído pelo departamento.
@Entity
public class Departamento{
   @Id private int id;
   @OneToMany(mappedBy="departamento")
   @MapKey(name="id")
                private Map funcionarios;
}
5 Chave é uma entidade e valor é um tipo básico
Exemplo: Atribuir a senioridade de cada funcionário no departamento em um contexto onde o funcionário pode atuar em vários departamentos e a senioridade podendo variar, uma vez que ela é determinada em função do departamento (um funcionário pode ser pleno no setor de desenvolvimento e junior no departamento de infraestrutura...).
@Entity
public class Department{

   @Id private int id;

   @ElementCollectionn
   @CollectionTable(name="emp_senioridade")
   @MapKeyJoinColumn(name="emp_id")
   @Column(name="senioridade")
   private Map<Employee, Integer> seniorites;
   // ...
}

Tuesday, June 6, 2017

Pool de Conexões em Aplicações Web

Aplicações Web que acessam bancos de dados precisam estar preparadas para receber uma avalanche de requisições ou correm sério risco de serem derrubadas. Considere também que estabelecer uma nova nova conexão com o banco de dados para cada requisição do cliente pode ser oneroso e consumir recursos desnecessários tornando esse processo mais lento e diminuindo a performance da aplicação. Imagine, por exemplo, 1 milhão de acessos simultâneos e a própria aplicação ter que ficar abrindo e fechando conexões para cada um...! Esse gargalo pode ser minimizado com uma técnica chamada pooling.

Outra vantagem é que o servidor passa a gerenciar a conexão com o banco de dados, e não mais a aplicação. O software do servidor implementa o conceito de Pool Manager que passa a ser um middleware entre os componentes clientes (uma classe java, uma servlet, EJB, etc) e uma conexão representada com driver JDBC  para algum servidor de banco de dados. Na prática, é criada uma camada adicional entre a aplicação e o servidor de banco de dados, essa camada é o Pool Manager.

O Pool Manager já abre um conjunto de conexões (pool) quando o servidor inicia e, de acordo com o número de requisições à aplicação, procura sempre se antecipar e manter um número maior de conexões disponíveis antes que as mesma sejam solicitadas.

Com o pooling, as operações de conexão são totalmente transparentes à aplicação, de modo que detalhes sobre o banco de dados (usuário, senha, etc), fechamento e abertura de conexões físicas, endereço do servidor de banco de dados, são administradas pelo pool manager. A seguir um exemplo dessa técnica.


Implementando Pooling no servidor GlassFish 4.1 para o MySQL

No MySQL crie um banco de dados chamado Study. Baixe o driver JDBC do MySQL, copie e cole-o no diretório <glassFishHome>/glassfish/lib.

Inicie o servidor GlassFish. Você pode inicia-lo facilmente através de alguma IDE, ou pelo shell (ou prompt) executando o comando abaixo conforme a imagem:
<glassFishHome>/glassfish4.1/bin/ ./asadmin start-domain


Após iniciar o servidor, abra seu browser e acesse a porta 4848, que é o painel de controle visual do servidor:




No menu em árvore à esquerda, navegue por Resources/JDBC/JDBC Connection Pools e clique em New:



No passo 1/2, dê um nome para o seu Pool, escolha javax.sql.Datasource na combobox resource type. E no drive vendor escolha MySql, que é o banco que escolhemos:



Clique em next.
No passo 2/2 marque habilitar ping e agora configuramos os dados da conexão. O painel apresenta duas centenas de parâmetros para informar, mas nosso interesse é apenas nos dados do usuário do banco, senha (se houver), nome do servidor, nome do banco, porta e URL. No meu caso, parâmetros e valores ficaram respectivamente como segue (faça as adpatações necessárias conforme o contexto de seu sistema):

password: 010203
databaseName: study
serverName: localhost
user: root
portNumber: 3306
URL: jdbc:mysql://:3306/study



Clique em Finish. Acesse sua conexão no menu JDBC/Connection Pools e clique em ping para testar a conexão. Se os parâmetros estiverem corretos o ping ira suceder como mostra a imagem:



Agora, no menu esquerdo vá em Resources/JDBC/JDBC Resources e New. Esse será o recurso que será acessado por nossa palicação. Em JNDI Name coloque jdbc/studyDS e na combo box pool name escolha o pool que você acabou de criar, StudyDB e salve.



Agora nosso recurso está disponivel na tabela JDBC Resources do servidor, como jdbc/studyDS. Guarde esse nome pois ele será informado em nossa aplicação.

Acessando o Pool com uma aplicação web

Com uma IDE de su preferência (usei NetBeans 8.2), crie um novo projeto Web Application chamado TestDataSource. Na pasta WEB-INF crie os arquivos web.xml e sun-web.xml. Cole as seguintes tags nos arquivos:

web.xml 
    <distributable/>
    <resource-ref>
        <description>JDBC Connection Pool</description>
        <res-ref-name>jdbc/studyDS</res-ref-name>
        <res-type>javax.sql.ConnectionPoolDataSource</res-type>
        <res-auth>Container</res-auth>
        <res-sharing-scope>Shareable</res-sharing-scope>
    </resource-ref>
sun-web.xml
<sun-web-app>
  <context-root>TestDataSource</context-root>
  <resource-ref>
    <res-ref-name>jdbc/studyDS</res-ref-name>
    <jndi-name>jdbc/studyDS</jndi-name> 
  </resource-ref>
</sun-web-app>
Neste exemplo o componente que irá solicitar conexão ao Pool Manager será uma servlet. Crie uma servlet mapeada para a url NewServlet:
@WebServlet(urlPatterns = {"/NewServlet"})
public class NewServlet extends HttpServlet {

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
      
        response.setContentType("text/html;charset=UTF-8");            

        try {
            PrintWriter out = response.getWriter();          
            Context ctx = new InitialContext();
//nome do recurso no servidor
         DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/studyDS");
//obtem a conexão do pool                       
            Connection connection = ds.getConnection();                       
//saida mostrando o nome do banco de dados acessado           
            out.println(connection.getCatalog());

           connection.close();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        processRequest(request, response);
    }
}
Salve, faça o deploy e acesse aplicação: http://localhost:8080/TestDataSource/NewServlet

Se tudo estiver certo, a aplicação mostra o nome do banco de dados, study pelo método getCatalog() do objeto connection:




Repare que em nenhum momento a própria aplicação toma maiores conhecimentos sobre o banco de dados, tais como usuário, senha, driver ou a localização do servidor, ela simplesmente pede uma conexão não importando de onde ou como ela vem, o que representa uma brecha de segurança a menos no sistema.

Existem formas ainda mais otimizadas para acessar o Pool utilizando as especificações JPA e CDI do JavaEE 7 através das anotações @PersistenceContext @Resource!

Wednesday, May 24, 2017

Adicionando Comandos ao PATH do Linux

Se você sabe em qual diretório está o comando que você quer executar, basta digitar o caminho até o arquivo sh e executar. Obviamente isso pode ser inconveniente caso o caminho seja muito longo. Uma forma mais prática é criar um script contendo o comando e seu caminho completo e adicioná-lo a váriável de ambiente PATH.

Alguns diretórios já estão previamente mapeados pelo PATH, de modo que basta colocar o script em alguns desses diretórios para que ele se torne visível de qualquer lugar.

Para saber quais diretórios estão mapeados pelo PATH, execute:
echo $PATH
Um resultado possível do comando é este:
/home/rafael/bin:/home/rafael/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin
Os diretórios mapeados estãos separados por dois-pontos.

Exemplo: Executando o servidor GlassFish pela PATH

Na minha máquina o caminho completo para executar o glassFish é

/usr/share/glassfish-4.1.2/bin/asadmin start-domain

Digite alt+F2+gedit+enter

Escreva este conteúdo no editor:
#!/bin/bash
# Script para executar o servidor GlassFish
/usr/share/glassfish-4.1.2/bin/asadmin
A primeira linha é importante e indica que o arquivo será usado como script de execução. Salve o arquivo em /home/bin (que é uma dos diretórios previamente mapeados por PATH) com o nome glassFish_4_1_2

Próximo passo é dar as permissões para que o script possa ser executado. Vá na pasta bin e execute:
chmod 775 glassFish_4_1_2
chmod (change mode) é o comando para alterar as permissões de arquivos. O comando recebe três parâmetros (775) onde o primeiro dígito (7) dá as permissões para o usuário local, o segundo dígito (7) as permissões para grupos de usuários, e o terceiro (5) para outros usuários. O valor 7 concede todas as permissões, leitura, escrita e execução.

Agora, de qualquer lugar do seu sistema, você iniciar o servidor apenas digitando o nome do arquivo que você salvou na pasta home/bin. Passe como parâmetro o valor start-domain, que inicia domínio default do servidor.


De qualquer browser acesse a porta 4848 e veja que a instância do servidor foi iniciada:



Observações

Às vezes ao executar um comando você pode receber uma mensagem de erro dizendo que o comando não foi localizado ou que você não tem permissão para fazer isso. Caso isso aconteça, verifique os seus privilégios, verifique se o comando foi digitado corretamente, utilize o comando sudo. Em algumas versõe do Linux a pasta home/bin pode não existir previamente, nesse caso você terá de criá-la. A versão de Linux utilizada neste post foi o Mint 18 Cinnamon.

Monday, May 8, 2017

E-Commerce com Servlets, JSP e JPA: parte 2

Na primeira parte do nosso projeto de loja virtual criamos as entidades e configuramos o framework de persistência Java Persistence API (JPA) que gerou automaticamente todas as tabelas no banco de dados e as respectivas relações entre elas a partir das classes no pacote model. Esse processo do JPA de gerar todas as tabelas prontamente configuradas no banco de dados é chamado de mapeamento objeto-relacional.

A camada de modelo dados de nosso projeto já está pronta. Nesta segunda parte vamos criar camada view, que é a camada responsável por gerar a interface de comunicação entre o usuário e a nossa aplicação. Para tanto utilizaremos os frameworks Java Server Pages (JSP) e Servlets.

O Diagrama de Casos de Uso abaixo nos mostra todas as possíveis ações que o usuário pode realizar no nosso sistema:


As ações em um diagrama de casos de uso podem ser mapeadas para um método na classse responsável, geralmente chamada service. Por exemplo, quando usuário selecionar uma categoria, o sistema deve mostrar-lhe algum tipo de lista contendo todos os produtos da categoria selecionada. Para satisfazer esse caso de uso poderíamos criar um método cuja assinatura é parecida com esta List<Product> getProducts(Categorie cat).

JSP: criando a interface com o usuário

Todas as páginas de nossa aplicação terão o design semelhante, com um cabeçalho, exibindo o nome da loja; um painel de menus do lado esquerdo, mostrando as categorias; e no centro o conteúdo variável, listas de produtos, descrições, carinho de compras, etc. Como mostrado na figura:



Com o NetBenas aberto crie a pasta pages dentro de Web Pages, que é onde ficarão todas as páginas web da nossa aplicação. Em seguida clique com o botão direito do mouse na pasta pagesnew, JSP... Crie as páginas:

  • header.jsp (o cabeçalho que será usado por todas as páginas)
  • menu.jsp (o menu lateral que será usado por todas as páginas)
  • home.jsp (página inicial)
  • productsByCat.jsp (exibe os produtos por filtrados por categoria)
  • productDetails.jsp (exibe os detalhes de um produto selecionado)
  • shoppingCart.jsp (exibe os produtos no carrinho de compras)
  • checkout.jsp (exibe os dados do pedido para o usuário confirmar a compra)
  • login.jsp (para fazer pedido usuário precisa fazer login)
  • register.jsp (para fazer login o usuário precisa informar os dados e cadastrar)
  • thankyou.jsp (mensagem de agradecimento após a compra)
Crie também um pacote chamado control. Dentro dele crie uma classe chamada ServletController. Está classe será responsável por gerenciar a navegação entre as páginas da aplicação:



Controlando navegação de páginas

Nossa aplicação segue o padrão Model-View-Controller (MVC). Uma servlet  intercepta toda requisição HTTP e encaminha a resposta para ser apresentada pela página JSP correspondente baseado na URL da requisição, nos input parameters e no estado da aplicação. O valor do parâmetro action em cada página JSP  define o comportamento da servlet.


ServletController

Declaração da classe e o método init():
//imports omitidos
//@WebServlet diz para o servidor que esta classe é uma servlet, e qual é a sua url no browser
//@WebInitParam indica parâmetros de inicialização
@WebServlet(name = "ServletController", urlPatterns = {"/servletController"},
                    initParams = {
                        @WebInitParam(name = "controller", value = "servletController"),
                        @WebInitParam(name = "imagesUrl", value = "images/")})
public class ServletController extends HttpServlet{

    @Override
    public void init(ServletConfig config) throws ServletException {

      //configura os parâmetros de inicialização em ServletContext,
      //de modo que eles ficarão acessíveis de qualquer parte da aplicação, em qualquer momento
        ServletContext context = config.getServletContext();
        context.setAttribute("controller", config.getInitParameter("controller"));
        context.setAttribute("imagesUrl", config.getInitParameter("imagesUrl"));
    }
}

O método doGet() geralmente é usado para exibir informações de consulta com base em parâmetros. Não é um método adequado para para enviar enviar informações sensíveis pois o valor dos parâmetros aparece na URL:
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

 //recebe o parâmetro action e com base no valor decide para qual página despachar
 String action = req.getParameter("action");
 String url = "/pages/home.jsp";
 
 if(action != null){

   //já existe uma sessão aberta
   ClientService clientService = (ClientService) req.getSession().getAttribute("clientService");
 
   if(action.equals("productsByCat")){
      url = "/pages/productsByCat.jsp";
      String categoryId = req.getParameter("categoryId");
      req.setAttribute("categoryId", categoryId); 
   }
   else if(action.equals("productDetails")){
      url = "/pages/productDetails.jsp";
      String productId = req.getParameter("productId");
      req.setAttribute("productId", productId);
   }
   else if(action.equals("addProductToCart")){ 
      clientService.addProductToCart(req.getParameter("productId"));
      url = "/pages/shoppingCart.jsp";
   }
   else if(action.equals("displayShoppingCart")){
      url = "/pages/shoppingCart.jsp";
   }

   //o usuário quer efetivar o pedido, mas antes precisa fazer login, 
   //se não tiver login, terá que se cadastrar
   else if(action.equals("checkout")){
      boolean logged = clientService.isLogged();
      if(logged)
         url = "/pages/checkout.jsp";
      else
         url = "/pages/login.jsp";
      }
      else if(action.equals("register")){
         url = "/pages/register.jsp";
      }
   }
   //direciona para a página adequada
   req.getRequestDispatcher(url).forward(req, resp); 
}

O método doPost() é usado para enviar informações de formulário. Na nossa aplicação ele utilizado para login, cadastro do usuário, finalizar o pedido e mudar o estado do carrinho de compras.
@Override
 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   //recupera action e decide o que fazer com base no valor 
   String action = req.getParameter("action");
   String url = "/pages/shoppingCart.jsp";
 
   if(action != null){
 
      ClientService clientService = (ClientService) req.getSession().getAttribute("clientService");
 
      if(action.equals("updateCart")){
         String quantity = req.getParameter("quantity");
         String productId = req.getParameter("productId"); 
         clientService.updateShoppingCart(productId, quantity);
      } 
      else if(action.equals("deleteProduct")){
         String productId = req.getParameter("productId");
         clientService.deleteProduct(productId);
     }
     else if(action.equals("register")){
        clientService.register(req); 
        url = "/pages/checkout.jsp"; 
     }
     else if(action.equals("checkout")){ 
        EOrder order = clientService.proceedCheckout();
        req.setAttribute("order", order);
        url = "/pages/thankyou.jsp";
     }
     else if(action.equals("login")){
        clientService.login(req.getParameter("email"), req.getParameter("login"));
        if(clientService.isLogged())
           url = "/pages/checkout.jsp";
        else
           url = "/pages/login.jsp";
        }
    } 
    req.getRequestDispatcher(url).forward(req, resp);
 }
Páginas JSP

As páginas header.jsp e menu.jsp estarão presentes em todas as páginas, de modo que elas serão páginas de composição através da declaração tag jsp:include nas outras páginas, assim não é necessário escrever o mesmo código repetidas vezes.

header.jsp
<center>
<table>
    <tr>
        <td><img src="${applicationScope['imagesUrl']}stark.png" style="width: 80px; height: 70px;" /></td>
        <td>
            <a href="${applicationScope['controller']}">
                <h4>STARK HOUSE E-commerce - BuyDigital!</h4>
            </a>   
        </td>
        <td>
            <a href="${applicationScope['controller']}?action=displayShoppingCart">
                <img src="${applicationScope['imagesUrl']}shopping_cart.png" style="width: 50px; height: 50px;" />
            </a>           
        </td>       
    </tr>
</table>
</center>
menu.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<jsp:useBean id="categoryService" class="business.CategoryService" scope="session"/>
<jsp:useBean id="clientService" class="business.ClientService" scope="session"/>
<form>
 <table>
     <c:if test="${clientService.logged}">
         <tr>
             Bem Vindo ${clientService.client.fullName}
         </tr>
     </c:if>             
    <tr>
        <td>
            <input type="text" name="search"/>           
        </td>
        <td><input type="button" value="SEARCH"/></td>
    </tr>   
    <c:forEach items="${categoryService.categories}" var="category">
        <tr>
            <td>
<!-- parâmetro action e categoryId são enviados à servlet controller quando o usuário usar este link -->
  <a href="${applicationScope['controller']}?action=productsByCat&categoryId=${category.id}">

                                                ${category.name}</a>
            </td>
        </tr>
    </c:forEach>    
 </table>      
</form>
Nas páginas JSP a expressão ${applicationScope['attributeName']} representa um atributo de contexto da apĺicação, aqueles mesmos que foram definidos no método initi() da Servlet. Como o próprio nome sugere, tais atributos têm escopo de aplicação, ficam disponíveis enquanto a aplicação rodar no servidor.

O valor do parâmetro action vai variando de acordo com o link do qual ele é enviado para o controller. Na página menu.jsp seu valor é productsByCat, indicando ao controller para carregar uma exibição de produtos filtrados por categoria. O id da categoria é informado em um segundo parâmetro chamado categoryId.

A tag jsp:useBean permite que você crie ou localize uma instância de uma classe. Como o escopo informado é sessão, o bean será criado apenas uma vez, e ficará diponível enquanto durar a sessão do usuário.

Home.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <title>JSP Page</title>
   </head>
   <body>
       <table style="border: 1px solid #cccccc; width: 1000px">
           <tr> 
               <td colspan="2"><jsp:include page="header.jsp" flush="true" /></td>
           </tr>
           <tr>
              <td><jsp:include page="menu.jsp" flush="true" /></td>
              <td> 
                   <img src="${applicationScope['imagesUrl']}store.jpg" style="width: 150px; height: 150px;" />
              </td>
          </tr>
       </table>
   </body>
</html>

productsByCat.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<jsp:useBean id="productService" class="business.ProductService" scope="session"/>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <table style="border: 1px solid #cccccc; width: 1000px">
            <tr>
               <td colspan="2"><jsp:include page="header.jsp" flush="true" /></td>
            </tr>
            <tr>
               <td><jsp:include page="menu.jsp" flush="true" /></td>
               <td> 
                  <table style="width: 500px">
                      <tr>
                          <th>Name</th> 
                          <th>Price</th>
                       </tr>
                      <c:forEach items="${productService.getProducts(requestScope.categoryId)}" var="product"> 
                          <tr>
                              <td>${product.name}</td>
                              <td>${product.price}</td>
                              <td>
         <a href="${applicationScope['controller']}?action=productDetails&productId=${product.id}">
                                 Details...</a>
                              </td>
                          </tr> 
                     </c:forEach>
                  </table> 
              </td>
           </tr>
        </table>
   </body>
</html>
A página productsByCat lista os produtos de uma categoria. A tag <c:ForEach/> realiza um loop pela coleção retornada pela chamada do método getProducts() do bean productService.

productsDetails.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<jsp:useBean id="productService" class="business.ProductService" scope="session"/>
<c:set var="product" value="${productService.getProduct(requestScope.productId)}" scope="request" />
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body> 
        <table style="border: 1px solid #cccccc; width: 1000px">
            <tr>
                <td colspan="2"><jsp:include page="header.jsp" flush="true" /></td>
            </tr>
            <tr>
               <td><jsp:include page="menu.jsp" flush="true" /></td>
            <td> 
                <table>
                    <th colspan="2">
                        ${product.name}
                    </th>
                    <tr>
                        <td colspan="2">${product.description}</td>
                    </tr>
                    <tr style="float: left;">
                        <td>Price $</td>
                        <td>${product.price}</td>
                    </tr>
                    <tr>
                        <td>
                            <a href="${applicationScope['controller']}?action=addProductToCart&productId=${product.id}">
                                Add To Cart</a>
                        </td>
                    </tr>
                 </table> 
              </td>
            </tr>
        </table>
    </body>
</html>
A tag <c:set/> permite que você assine um valor para um objeto Y ou uma variável qualquer. Você deve referenciar essa variável no restante da página por meio da Expression Language (EL) ${Y}.

shoppingCart.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<jsp:useBean id="clientService" class="business.ClientService" scope="session"/>
<jsp:useBean id="productService" class="business.ProductService" scope="session"/>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>               
        <table style="border: 1px solid #cccccc; width: 1000px">
            <tr>
                <td colspan="2"><jsp:include page="header.jsp" flush="true" /></td>
            </tr>           
             <tr>
                <td><jsp:include page="menu.jsp" flush="true" /></td>
                <td>
                    <c:if test="${clientService.shoppingCart.size() != null}" >
                    <table>
                        <tr>
                        <th>Name</th>
                        <th>Description</th>
                        <th>Price</th>
                        <th>Quantity</th>
                        <th>Subtotal</th>                       
                        </tr>
                        <c:forEach items="${clientService.shoppingCart.keySet()}" var="idProduct" >                           
                            <c:set var="product" value="${productService.getProduct(idProduct)}" />
                            <tr>
                                <td>${product.name}</td>
                                <td>${product.description}</td>
                                <td>${product.price}</td>                               
                                <form method="post" action="${applicationScope['controller']}">
                                <td>
                                    <input type="hidden" name="action" value="updateCart" />
                                    <input type="text" name="quantity" size="2"
                                           value="${clientService.shoppingCart.get(product.id)}" />
                                </td>
                                <td>${(product.price * clientService.shoppingCart.get(product.id))}</td>
                                <td>                                   
                                    <input type="submit" value="Update" />
                                    <input type="hidden" name="productId" value="${product.id}" />
                                    <input type="hidden" name="action" value="updateShoppingCart" />                                   
                                </td>
                                </form>
                                <form method="post" action="${applicationScope['controller']}">
                                <td>                                   
                                    <input type="submit" value="Delete" />
                                    <input type="hidden" name="productId" value="${product.id}" />
                                    <input type="hidden" name="action" value="deleteProduct" />                                   
                                </td>
                                </form>
                            </tr>                           
                        </c:forEach>
                    </table>
<a href="${applicationScope['controller']}?action=checkout" >Proceed Checkout</a>
                    </c:if>
                    <c:if test="${clientService.shoppingCart == null}">            
                        Shopping Cart is Empty!            
                    </c:if>
                </td>
             </tr>                       
        </table>       
    </body>
</html>
shoppingCart.jsp representa o carrinho de compras. A medida em que o usuário escolhe os produtos, eles são armazenados na sessão na forma de um map chave/valor representando produto/quantidade respectivamente. Não é uma boa prática utilizar código java puro em paginas JSP, dê prefêrencia para as tagLibs JSTL, como temos feitos até agora com as tags <c:if>, <c:set><c:forEach> etc.

checkout.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<jsp:useBean id="clientService" class="business.ClientService" scope="session"/>
<c:set var="client" value="${clientService.getClient()}" scope="request"  />

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Register</title>
    </head>
    <body>
        <table  align="center">
            <tr>
                <td>
                    <jsp:include page="header.jsp" flush="true" />
                </td>
            </tr>    
        <tr>        
        <td>
            <form method="post" action="${applicationScope['controller']}">
            <input type="hidden" name="action" value="checkout"/>
            <table  style="border: 1px solid #cccccc; width: 450px;">
                <tr>
                    <td>Name:</td>
                    <td colspan="3">${client.fullName}</td>
                </tr>
                <tr>
                    <td>Email</td>
                    <td colspan="3">${client.email}</td>
                </tr>
                <tr>
                    <td align="center" colspan="4"><b>Your Order Details</b></td>                    
                </tr>
                <tr style="font-weight: bold;">
                    <td>Product</td>
                    <td>Price</td>
                    <td>Quantity</td>
                    <td>Total Item</td>
                </tr>
                <c:forEach items="${clientService.shoppingCart.keySet()}" var="idProduct" >                    
                    <c:set var="product" value="${productService.getProduct(idProduct)}" />                    
                    <tr>
                        <td>${product.name}</td>
                        <td>${product.price}</td>
                        <td>${clientService.shoppingCart.get(product.id)}</td>
                        <td>${(product.price * clientService.shoppingCart.get(product.id))}</td>
                    </tr>                  
                </c:forEach>
                <tr>
                    <td colspan="2">Total Order</td>
                    <td colspan="2">${clientService.totalOrder}</td>
                </tr>
                <tr>
                    <td colspan="2">Credit Card Number:</td>
                    <td colspan="2">${client.creditCard}</td>
                </tr>
                <tr>
                    <td colspan="4"><input type="submit" value="Confirm Order"/></td>
                </tr>
            </table>
        </form>
        </td>
        </tr>
        </table>
    </body>
</html>
checkout.jsp exibe um formulário com todos os item que o usário escolheu e o valor total do pedido.

login.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <table style="border: 1px solid #cccccc; width: 1000px">
            <tr>
                <td colspan="2"><jsp:include page="header.jsp" flush="true" /></td>=
            </tr>
            <tr>
                <td><jsp:include page="menu.jsp" flush="true" /></td>
                <td> 
                    <table>
                    <form method="post" action="${applicationScope['controller']}">
                        <input type="hidden" name="action" value="login"/>
                        <tr>
                            <th colspan="2">Log in to preceed your Checkout</th>
                        </tr>
                        <tr>
                            <td>Email</td>
                            <td><input type="text" name="email" /></td>
                        </tr>
                        <tr>
                            <td>Login</td>
                            <td><input type="text" name="login" /></td>
                        </tr>
                        <tr>
                            <td><input type="submit" value="Login"/></td> 
                        </tr>
                        <tr>
                            <th colspan="2">
   <a href="${applicationScope['controller']}?action=register">Not Registered Yet?</a>
                            </th>
                        </tr>
                    </form>
                    </table>
                </td>
            </tr>
        </table>
    </body>
</html>
login.jsp pede para que o usuário faça login antes de emitir o pedido, caso ele não seja cadastrado, terá que fazê-lo no formulário de registro.

register.jsp
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<jsp:useBean id="clientService" class="business.ClientService" scope="session"/>
<jsp:useBean id="productService" class="business.ProductService" scope="session"/>

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>                
        <table style="border: 1px solid #cccccc; width: 1000px">
            <tr>
                <td colspan="2"><jsp:include page="header.jsp" flush="true" /></td>
            </tr>
            <tr>
                <td><jsp:include page="menu.jsp" flush="true" /></td>
                <td>                     
            <form action="${applicationScope['controller']}" method="post">
            <input type="hidden" name="action" value="register"/>
            <table>
                <tr>
                    <th colspan="4">Informations Required to Proceed Checkout</th>
                </tr>
                <tr>
                    <td>First Name</td>
                    <td colspan="3"><input type="text" name="fName" required="true" /></td>
                </tr>
                <tr>
                    <td>Last Name</td>
                    <td colspan="3"><input type="text" name="lName" required="true" /></td>
                </tr>
                <tr>
                    <td>Birth Date</td>
       <td colspan="3"><input type="text" name="birthDate" required="true" />dd/mm/yyyy</td>
                </tr>
                <tr>
                    <td>Email</td>
                    <td><input type="text" name="email" required="true" /></td>
                    <td>Login</td>
                    <td><input type="text" name="login" required="true"/></td>
                </tr>
                <tr>
                    <td>Credit Card</td>
                    <td colspan="3"><input type="text" name="creditCard" required="true" /></td>
                </tr>
                <tr>
                    <td colspan="4">
                        <input type="submit" value="Register" />
                    </td>
                </tr>
            </table>
        </form>
                </td>
            </tr>
        </table>        
    </body>
</html>
thankyou.jsp exibe uma mensagem de agradecimento após o usuário terminar o pedido:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<c:set var="order" value="${requestScope.order}" scope="request"  />
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <table style="border: 1px solid #cccccc; width: 1000px">
            <tr>
                <td colspan="2"><jsp:include page="header.jsp" flush="true" /></td>
            </tr>
            <tr>
                <td><jsp:include page="menu.jsp" flush="true" /></td>
                <td> 
                    Thank You for purchasing, ${order.client.firstName}!<br/>
                    Your order ID is ${order.id}, you will receive a confirmation at ${order.client.email}!
                </td>
            </tr>
        </table>
    </body>
</html>
Uma outra estrátégia para enviar o parâmetro action para a ServletController é utilizar campos escondidos com a tag input como por exemplo esta definição na página checkout.jsp
<input type="hidden" name="action" value="checkout"/>

Neste ponto, o projeto não compila porque ela faz referência aos beans de serviço que ainda não foram criados, como a classe ClientService por exemplo. Essas classes serão implementadas na parte 3 do artigo.

Referências
KURNIAWAN, Budi. Java for the Web with Servlets, JSP, and EJB: A Developer's Guide to Scalable J2EE Solutions. 1. ed. Indianapolis: New Riders, 2002. 903 p.
PATZER, Andrew. Foundations of JSP Design Patterns. 1. ed. Berkeley: Apress, 2004. 282 p.