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 e @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 pages, new, 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.

Falhas na interface gráfica do JasperStudio 6.3.1 no Ubuntu 16

Há diversas falhas na interface gráfica do gerador de relatórios JasperStudio 6.x rodando no Ubuntu 16.x. Um exemplo é mostrado na figura abaixo:


Repare que na área em destaque os componentes da janela Outline ficam invisíveis.

Trata-se de um problema de compatibilidade entre o Eclipse e a versão do toolkit de criação de interface gráfica GTK no Ubuntu 16 (pelo menos).

Para corrigir esse problema, vá até o diretório de instalação do JasperStudio e abra o arquivo runubuntu.sh. Insira o comando export para o toolkit. O arquivo runubuntu.sh deve ficar assim:
#!/bin/bash
export SWT_GTK3=0
DIR=$(dirname "$0")
export UBUNTU_MENUPROXY=0;
"$DIR"/Jaspersoft\ Studio $*
Salve e feche o arquivo. Execute novamente o JasperStudio:
/usr/local/TIBCOJaspersoftStudio-6.3.1.final/runubuntu.sh

Resolvido.

Monday, April 24, 2017

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

Com certeza você já utilizou os serviços de alguma loja virtual e, portanto, deve saber como funciona o processo de compra na web. Não importa em qual loja você esteja comprando, todas elas funcionam da mesma forma, isto é, toda especificação para um sistema de e-commerce tem requisitos essenciais que estão presentes em todos eles. Por exemplo, toda loja online deve permitir que o usuário que a visita possa realizar as seguintes ações:
  • Pesquisar por algum produto baseado no nome ou na descrição
  • Navegar através de uma lista de produtos classificados por categoria
  • Selecionar um produto e ver seus detalhes
  • Colocar o produto em um carrinho de compras
  • Ver e alterar os produtos que estão no carrinho de compras
  • Fazer o pedido e finalizar a compra
Ao longo de 3 posts desenvolveremos um projeto com as especificações acima chamado Stark House E-Commerce. Utilizaremos os frameworks JavaEE Servlets, JSP e JPA junto na IDE NetBeans 8. O banco de dados será o PostgreSQL.

JPA: Modelando o negócio e criando o banco de dados

Java Persistence API (JPA) é a especificação padrão Java EE para persistencia de dados. O JPA realiza sozinho todo mapeamento a partir do modelo orientado a objetos e constrói toda base de dados relacional independente do banco dados que a aplicação vá utilizar.

O diagrama de classes abaixo nos mostra como será o modelo de negócios do projeto:


Um cliente pode realizar vários pedidos. Cada pedido é feito por apenas um cliente. Uma categoria tem vários produtos. Cada produto pertence a somente uma categoria. Um pedido pode ter vários produtos e um produto pode estar em vários pedidos.

Produtos e Pedidos representam uma relação muitos-para-muitos. Esse tipo de relação precisa ser normnalizado. Assim, criamos a classe orderProduct que contem a quantidade de itens de um pedido e o subtotal (mais sobre normalização em seguida...).

Codificando o modelo (para clareza, as declarações import foram omitidas)

Abra a IDE NetBeans, crie um novo projeto Java Web, dê o nome de StarkHouseECommerce e finalize. Delete o arquivo index.html que o NetBeans cria automaticamente.
Para utilizar o JPA você precisa ter as seguintes biblioteca no seu classpath, conforme a imagem da janela de projetos do NetBeans:


Você pode baixar as bibliotecas aqui hibernate 4.3.5.Final (todos os arquivos na pasta /lib/required). Também deve usar esta hibernate-entitymanager. E o driver do banco de dados PostgreSQL.

A especificação do JPA nos diz que precisamos ter o arquivo persistence.xml no projeto. É nele que ficam as informações de acesso ao banco de dados. No nosso exemplo, o arquivo deve ser como segue:
<?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="ecommerce" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <properties>
      <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/ecommerce"/>
      <property name="javax.persistence.jdbc.user" value="postgres"/>
      <property name="javax.persistence.jdbc.password" value="postgres"/>
      <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver"/>           
      <property name="hibernate.show_sql" value="true"/>
      <property name="hibernate.format_sql" value="true"/>
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
    </properties>
  </persistence-unit>
</persistence>
No meu banco, usuário e senha são ambos postgres. E a porta geralmente é 5432. Se no seu caso for diferente, apenas faça as adequações. Crie um banco de dados chamado ecommerce.

Criando as Entidades

Classe EClient.java, a entidade que realiza as compras no nosso site.
//imports omitidos 
@Entity
@Table(name = "eclient")
public class EClient implements Serializable{   

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;   //chave primária gerada sequencialmente
    @Column
    private String firstName;   
    @Column
    private String lastName;  
    @Column @Temporal(TemporalType.TIMESTAMP)
    private Date birthDate;   //campo tipo data e tempo
    @Column
    private String creditCard;   
    @Column
    private String email;   
    @Column
    private String login;  

//esta anotação indica uma relação "um-pra-muitos" entre cliente e pedido
    @OneToMany(mappedBy = "client")
    private List<EOrder> orders;

//construtor
    public EClient() {
        orders = new ArrayList<>();
    }
    //getters & setters para cada atributo
}
A classe EOrder que representa os pedidos do nosso sistema:
@Entity
public class EOrder {
   
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;  
    @Column
    @Temporal(TemporalType.TIMESTAMP)
    private Date date;  

    @ManyToOne   //cada pedido pertence a um cliente
    @JoinColumn(name = "CLI_ID")  //equivale a chave estrangeira da classe EClient
    private EClient client;  

    @OneToMany(mappedBy = "eorder")  //um pedido tem muitos produtos
    private List<OrderProduct> orderProduct;

    public EOrder() {
        client = new EClient();
        orderProduct = new ArrayList<>();
    }
//getters e setters omitidos
}
A classe Product:
@Entity
@Table(name = "product")
public class Product {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;   
    @Column
    private String name;   
    @Column
    private Double price;   
    @Column
    private String description;   

    @ManyToOne  //cada produto pertence a uma categoria
    @JoinColumn(name = "CAT_ID", nullable = false) //chave estrangeira de Category
    private Category category;   

    @OneToMany(mappedBy = "product") //um produto está em muitos pedidos
    private List<OrderProduct> orderProduct;

    public Product() {
        category = new Category();
        orderProduct = new ArrayList<>();
    }
//getters e setters omitidos
}
Normalizando a relação Produto e Pedido

De acordo com o nosso digrama de classes, Product e EOrder têm entre si uma relação N para N, isto é, muitos-para-muitos. Esse tipo de relação só existe conceitualmente, na hora de implementar precisamos normaliza-la, tranformando-a em 2 relações 1 para N, uma-para-muitos. Dessa forma, criamos uma classe extra para armazenar a quantidade de produtos de cada pedido, bem como o subtotal (o cliente pode ter ganho um desconto no dia do pedido, mas o preço real do produto continua inalterado na base de dados, por exemplo). Criamos a classe OrderProduct, a qual possui uma referência tanto para Product quanto para EOrder, mais os campos quantity e total.

De acordo com a especificação do JPA, o ID dessa nova entidade deve ficar em uma classe separada, vamos chamá-la de OrderProductId:
@Entity
@IdClass(OrderProductId.class) //indica a classeId de OrderProduct
public class OrderProduct {

    @Id
    @ManyToOne
    @JoinColumn(name = "prd_id")
    Product product;
   
    @Id
    @ManyToOne
    @JoinColumn(name = "ord_id")
    EOrder eorder;
   
    @Column
    private Integer quantity;  //a quantidade de produtos no pedido
    @Column     //valor total deste produto no pedido, geralmente preço x quantidade
    private Double total;  

    //getters e setters omitidos
}
A classe OrderProductId:
public class OrderProductId implements Serializable{
   
    int eorder;
    int product;
    //getters e setters omitidos
//é obrigatório a implementação dos métodos hashCode() e equals() utilizando os dois campos
}
A classe Category:
@Entity
@Table(name = "category")
public class Category {  

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column
    private String name;

    @OneToMany(mappedBy = "category", fetch = FetchType.LAZY)
    private List<Product> products;  //uma categoria tem muitos produtos

    public Category() {
        products = new ArrayList<>();
    }
//getters e setters omitidos
}
Populando o banco de dados

Agora que temos todo o modelo pronto, é hora de popular as tabelas do banco de dados. Não se esqueça de criar um banco de dados chamado ecommerce. O JPA criará todas as tabelas e os relacionamentos para você.

Para preencher as tabelas crie uma classe chamada teste com um método principal e execute-a:
public class teste {

    public static void main(String[] args) {

//"ecommerce" é o nome da unidade de persistencia conforme definido no arquivo persistence.xml
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("ecommerce");
        EntityManager em = emf.createEntityManager();

//criando as categorias
        Category eletronicos = new Category("eletrônicos", null);
        Category suplementos = new Category("suplementos", null);
        Category livros = new Category("livros", null);
       
//criando os produtos e passando a respectiva categoria no construtor
        Product ps4 = new Product("PS4", 566.23,
                "Adquira o PS4™ e prepare-se para a experiência de jogo mais imersiva possível!", eletronicos);
        Product noteDell = new Product("NoteBook Dell", 303.99, "Linux, 15.6, 8GB, i7", eletronicos);
        Product IPhone = new Product("IPhone 5S", 299.99, "16GB, 4G, Explore o mundo do iPhone!", eletronicos);
       
        Product wheyProt = new Product("Whey Protein ON", 32.01, "Whey Protein Isolada ON. Rápida absorção", suplementos);
        Product multiAz = new Product("Multi AZ Final", 11.0, "Multi AZ para homens e mulheres", suplementos);
        Product omega3 = new Product("Omega 3", 65.99, "Puro Omega 3 importado 120 caps", suplementos);
       
        Product javaHowTo = new Product("Java como Programar", 80.15, "Java como Programar, Deitel, Deitel, 1100 páginas", livros);
        Product jsf = new Product("Core JSF", 80.15, "Core JSF, Geary Horstmann, 400 páginas", livros);
        Product cronicasGeloFogo = new Product("Crônicas de Gelo e Fogo", 55.88, "O Festim dos Corvos, RR Martin, 800 páginas", livros);
       
//antes de salvar as categorias e os produtos, precisamos abrir uma transação
        em.getTransaction().begin();      

//persist() é o método de EntityManger para persistir os objetos no banco
        em.persist(eletronicos);
        em.persist(suplementos);
        em.persist(livros);       

        em.persist(ps4);
        em.persist(noteDell);
        em.persist(IPhone);
        em.persist(wheyProt);
        em.persist(multiAz);
        em.persist(omega3);
        em.persist(javaHowTo);
        em.persist(jsf);
        em.persist(cronicasGeloFogo);
       
 //para finalizar confirme a transação e feche os recursos utilizados  
        em.getTransaction().commit();               
        emf.close();
    }
}
Repare como ficou nossa janela de projetos no NetBans. Repare também que no console da IDE o JPA exibe as declarações sql que foram geradas no banco:



O JPA nos auxilia na construção do modelo e no relacionamento com o banco de dados.

O próximo passo na parte 2 deste artigo é criar a interface com o usuário para que ele possa se cadastrar e comprar os produtos registrados em nosso banco de dados. Para nos auxiliar nesse tarefa utilizaremos os frameworks Servlets e Java Server Pages (JSP)!

Tuesday, April 4, 2017

Adapter Design Pattern

Em engenharia de software, o padrão de projeto Adapter permite que você trabalhe com novas implementações sem modificar o código já existente. Por exemplo, se um framework utilizado pelo sistema é atualizado e algumas interfaces são alteradas nessa nova versão, você pode utilizar o padrão Adapter para permitir que o sistema acesse as novas funcionalidades sem alterar o código existente.

Resumidamente o padrão Adapter permite que duas interfaces incompatíveis, mas com funcionalidades semelhantes, trabalhem juntas.

O padrão Adapter é fácil de entender porque o mundo real está repleto de dele!

Exemplo

Suponha que você tenha uma ChaveA que abre uma FechaduraA. Conceitualmente a fechadura é a interface que exige uma determinada chave para que a porta seja aberta:


O código em java do diagrama anterior:
public class ChaveA {
    //atributos e métodos
}
public interface FechaduraA {

    void open(ChaveA chaveA);
}
public class FechaduraAImpl implements FechaduraA{

    @Override
    public void open(ChaveA chaveA) {
        System.out.println("Fechadura A aberta!");
    }   
}
E a classe cliente que contém o método main():
public class Cliente {

    public static void main(String[] args) {

        FechaduraA fechaduraA = new FechaduraAImpl();
        ChaveA chaveA = new ChaveA();
        open(fechaduraA, chaveA);
    }
    //requer como parâmetro uma FechaduraA e uma ChaveA para abrir
    static void abrir(FechaduraA fechaduraA, ChaveA chaveA){

        fechaduraA.open(chaveA);
    }   
}
Chamando o método main() na classe Cliente conseguimos abrir a fechadura sem problema. A saída é como segue:
Fechadura A aberta!
O método estático abrir() na classe Cliente exige dois argumentos, um objeto Fechadura e outro objeto do tipo Chave para então invocar o método open() da fechadura.

Imagine que apareça no mercado um novo padrão de fechaduras, o qual requeira também um novo tipo de chave.
public interface NovoPadraoFechaduraA {

    void open(ChaveB chaveB);
}
public class ChaveB {
    //código da classe B
}
E uma implementação concreta da interface NovoPadrãoFechaduraA:
public class NovoPadraoFechaduraAImpl implements NovoPadraoFechaduraA{

    @Override
    public void open(ChaveB chaveB) {
        System.out.println("Novo Padrão Fechadura A aberta!");
    }   
}

Seu sistema precisa implementar esse novo padrão, porém outras partes da aplicação continurão a usar o modelo antigo. Assim surge a questão: como atender a nova demanda sem prejudicar as outras partes que utilizam o padrão antigo? Em outras palavras, você precisa implementar o novo padrão, mas não poderá modificar o método estático abrir() da classe Cliente, o qual exige os modelos antigos de fechadura e chave!

O padrão Adapter resolve de forma eficiente essa questão. Ele torna possível utilizar as novas interfaces sem alterar o método abrir(). Para isso apenas precisamos criar uma classe que implemente a interface FechaduraA e também utilize as funcionalidades da interface da interface NovoPadraoFechaduraA. Chamemos esta classe de ChaveAAdaptador:

Código da classe Adapter:
public class ChaveAAdaptador implements FechaduraA{

    NovoPadraoFechaduraA novoPadrao;
    ChaveB chaveB;

    public ChaveAAdaptador(NovoPadraoFechaduraA fechadura) {       

        this.novoPadrao = fechadura;
        this.chaveB = new ChaveB();
    }   
    @Override
    public void open(ChaveA chaveA) {

        this.novoPadrao.open(chaveB);       
    }       
}
Instanciamos o adaptador na classe Cliente e podemos usar o novo padrão sem alterar o método abrir():
public class Cliente {
 
    public static void main(String[] args) {
        //modelo antigo
        FechaduraA fechaduraA = new FechaduraAImpl();
        ChaveA chaveA = new ChaveA();
        abrir(fechaduraA, chaveA);     
        //novo padrão
        NovoPadraoFechaduraA novoPadraoFechaduraA = new NovoPadraoFechaduraAImpl();
        ChaveAAdaptador adaptador = new ChaveAAdaptador(novoPadraoFechaduraA);
        abrir(adaptador, chaveA);
    }
  
    static void abrir(FechaduraA fechaduraA, ChaveA chaveA){

        fechaduraA.open(chaveA);
    }   
}
saída
Fechadura A aberta!
Novo Padrão Fechadura A aberta!

Monday, March 27, 2017

Acessando uma pasta compartilhada pelo Windows no Linux

Em plataformas Unix e similares, sistemas de arquivos em diferentes partições e unidades removíveis como cds, dvds, usbs podem ser anexados à árvore de diretórios através do comando mount.

Digamos que um servidor Windows compartilha uma pasta chamada subversion. Para acessar essa pasta de uma máquina Linux, execute o seguinte comando dentro da pasta /mnt (que é o local onde esses anexos temporários devem ficar):
sudo mount -t cifs //ip_doservidor_windows/subversion -o username=serverUser,password=serverPassword /mnt/share
  • share é o nome da pasta que irá representar no Linux a pasta que o Windows está compartilhando.
  • -t (type) deve ser seguido pelo tipo de sistema de arquivos com o qual o servidor trabalha, neste caso cifs (Common Internet File Systems), um protocolo para compartilhamento de recursos entre os nós de uma rede.