Muito tem sido comentado recentemente sobre a computação em nuvem, ou “cloud computing”. Uma de suas principais características é fazer com que um software, ou recurso, seja disponibilizado pela Internet e utilizado como um serviço, e não simplesmente como um produto (no sentido tradicional – o de comprar um software em uma “caixinha” e utilizá-lo por tempo indeterminado). Dentro deste modelo, se encaixam aplicativos tradicionais e outros tipos de serviços, como armazenamento de dados, fornecimento de conteúdo, mídia, ferramentas de colaboração e comunicação, entre outros.
A forma de acesso a estes aplicativos e recursos é geralmente feita por meio do navegador, mas também pode envolver o uso de uma aplicação cliente simplificada, criada para esta finalidade. Os softwares e dados são armazenados em servidores remotos, e a conexão a estes é feita pela Internet. Dessa maneira, o usuário tem a sensação de estar utilizando estes softwares e recursos localmente, sem ter necessariamente que conhecer detalhes sobre a localização e forma de acesso a eles.
Na Figura 1 pode ser observado que, aquilo que é chamado de “nuvem”, nada mais é que um conjunto de recursos disponibilizados por servidores espalhados pela Internet. Aliás, o termo nuvem é empregado como uma referência simbólica à Internet antes mesmo do estabelecimento do conceito de “Cloud Computing”.
O usuário, de posse de um computador desktop, notebook, tablet ou smartphone, terá de forma transparente o acesso a uma variedade de aplicações e dados compartilhados. A “nuvem” esconde a origem da aplicação ou informação; para o utilizador, é como se estes estivessem disponíveis localmente no dispositivo.
Outra característica importante da computação em nuvem é que uma informação adicionada ou alterada em um dos dispositivos será, de forma transparente, compartilhada pelos demais. Ou seja, qualquer que seja a forma de acesso, as aplicações e os dados disponíveis ao usuário serão os mesmos.
A computação em nuvem é utilizada hoje em três modelos:
• SaaS (Software as a Service): ou software como um serviço, neste esquema, os fornecedores do recurso em nuvem disponibilizam o acesso a aplicações completas aos clientes. É geralmente cobrada uma taxa de assinatura para o uso do serviço;
• IaaS (Infrastructure as a Service): neste caso, as empresas fornecedoras disponibilizam infraestrutura física para o serviço em nuvem, como servidores dedicados ou virtuais, segurança por meio de firewalls e até mesmo redes de acesso completas;
• PaaS (Platform as a Service): aqui, é fornecida uma plataforma para criação de aplicações em nuvem, que fica a disposição do desenvolvedor para criar seu aplicativo. Engloba geralmente uma linguagem de programação a ser utilizada para o desenvolvimento, APIs, acesso a banco de dados e um servidor Web. Este é o modelo adotado pelo Google App Engine, um serviço de aplicações em nuvem recentemente disponibilizado pelo Google.
Para o desenvolvimento de aplicações Java na nuvem, o Google App Engine é uma excelente opção: gratuito (desde que a aplicação seja mantida dentro de um limite máximo de acessos), eficiente e fácil de ser utilizado, com suporte a frameworks e tecnologias Java amplamente conhecidas como JSP, Servlets e JPA.
Conhecendo melhor e se inscrevendo no Google App Engine
O Google App Engine, ou somente GAE, é uma plataforma de desenvolvimento de aplicações em nuvem criada e disponibilizada pelo Google. É uma PaaS completa, que oferece não apenas uma, mas três linguagens de programação para criação dos aplicativos: Java, Python e Go.
No caso do desenvolvimento em Java, como mencionado anteriormente, a plataforma possui suporte completo a JSP e Servlets. Dados podem ser armazenados na própria plataforma (seu serviço datastore) facilmente utilizando a JPA (Java Persistence API). Além destes recursos, o desenvolvedor conta com toda a infraestrutura de datacenters e links redundantes do Google para dar suporte ao funcionamento do aplicativo. De acordo com o próprio Google, a estrutura destinada ao App Engine possui escalabilidade automática e cresce dinamicamente, à medida que for necessário à aplicação. Se o aplicativo precisa ter capacidade para mais usuários, ou necessita de mais armazenamento, o Google App Engine será escalonado proporcionalmente à demanda.
Apesar de tantos pontos positivos, existem algumas restrições no uso do App Engine, por exemplo:
• Aplicações não podem utilizar Threads;
• Componentes Swing e AWT não são suportados;
• Aplicações hospedadas no plano gratuito padrão têm um limite de 5 milhões de views.
Para utilizar o App Engine, o primeiro passo é possuir uma Conta Google. Se você já tem uma, basta acessar o endereço abaixo e se inscrever no App Engine:
https://appengine.google.com/
No momento do cadastro, será necessário informar o número de um telefone celular, para o qual será enviado um código de confirmação (Figura 2). Tome cuidado para fornecer um número válido, incluindo o código do país (+55) e o código da área (DDD), no formato: +55-XX-NNNN-NNNN substituindo XX pelo seu DDD e colocando o número do aparelho em seguida.
O código deve chegar por uma mensagem SMS em poucos instantes no seu aparelho. Ele deverá ser fornecido na tela da Figura 3.
Clicando no botão Send, o código será validado. Se estiver correto, a conta no App Engine será ativada e, em seguida, será necessário criar uma identificação para nosso primeiro aplicativo (Figura 4).
Nosso sistema será um simples gerenciador de contas, para que o usuário consiga gerenciar o que ainda precisa pagar. Como pode ser observado na Figura 4, usar um nome “genérico” para o identificador da aplicação (application identifier) como “contas”, provavelmente não é uma boa ideia. Estes identificadores devem ser únicos dentro do domínio padrão dos aplicativos instalados no App Engine (appspot.com). Assim, ao clicar em Check Availability, será feita uma verificação se o nome escolhido está disponível. Uma boa ideia é usar um nome genérico seguido do seu nome de usuário no Google. Por sua vez, o título do aplicativo, indicado em “Application Title”, não precisa ser único. Fique à vontade ao escolhê-lo.
Após digitar os dados, clique no botão “Create Application”. Será exibida uma tela indicando que o identificador da aplicação foi criado com sucesso. Anote o identificador escolhido, pois essa informação será necessária no momento do envio do projeto finalizado.
Pronto! Agora o Google App Engine já “sabe” sobre o nosso projeto, e podemos partir para o que interessa: a programação.
Instalando o Google Plugin no Eclipse
Um aplicativo para o Google App Engine pode ser desenvolvido com qualquer ambiente de desenvolvimento integrado, até mesmo com um simples editor de texto. Contudo, o Google Plugin, existente para o Eclipse, facilita em muito a criação do aplicativo, automatizando tarefas tediosas e sujeitas a erro, como a criação de arquivos XML. Neste artigo, utilizaremos o plugin para agilizar a criação de nossa aplicação exemplo.
Para instalar o plug-in necessário, abra o Eclipse e clique em Help | Install New Software... Na parte superior da janela que será aberta (Figura 5), clique no botão Add, ao lado da caixa de entrada de texto Work With, para adicionar o endereço de download do Google Plugin.
Após clicar no botão Add, uma nova janela será exibida. Digite dentro dela os dados exibidos na Figura 6 e clique em OK.
Com o novo local de download especificado, serão exibidas as opções de download disponíveis. Para desenvolvimento de um aplicativo direcionado ao Google App Engine, são necessários os componentes indicados na Figura 7 – marque-os e clique em Next.
Na tela seguinte, será solicitada uma confirmação dos componentes que serão instalados – apenas clique em Next. A próxima tela requer que os termos de licenciamento dos plug-ins sejam aceitos. Marque a opção “I accept the terms of the license agreement” para concordar e clique em Finish. Caso seja exibida a janela de aviso da Figura 8, indicando que o software não está assinado digitalmente, apenas ignore, clicando em OK.
Finalmente, depois de encerrado o download e instalação do plugin, a janela da Figura 9 será mostrada, solicitando a reinicialização do Eclipse. Clique em Restart Now. O Eclipse será então reiniciado.
Criando o aplicativo no Eclipse
O projeto exemplo que criaremos no Eclipse usando o GAE, como já informado, é um sistema simples para gerenciamento das contas que o usuário tem a pagar. Portanto, o usuário cadastra uma conta como pagamento pendente, especificando uma descrição, valor, data de vencimento e, opcionalmente, a linha digitável do código de barras, para facilitar o pagamento. À medida que as contas são pagas, estas são “baixadas” no sistema, e consequentemente removidas da lista. O aspecto final da aplicação será semelhante ao da Figura 10.
Para armazenamento das contas no datastore da App Engine, utilizaremos o framework Java JPA (Java Persistence API).
JPA: JPA (Java Persistence API) é um framework Java para persistência de objetos em bancos de dados relacionais. A API é definida dentro do pacote javax.persistence.
Utilizando JPA, classes que serão armazenadas em um banco relacional são definidas como Entities (entidades). A especificação de uma classe como Entity, assim como os metadados associados a ela e ao banco de dados relacional, são especificadas por annotations (declarações iniciadas com @) no código Java.
Uma linguagem denominada JPQL (Java Persistence Query Language) é utilizada para realização de consultas nas entidades armazenadas no banco de dados relacional.
Após a instalação do plugin, um novo botão para criação de projetos baseados em tecnologias Google aparecerá na barra de ferramentas do Eclipse. Clique neste botão (um esfera azul com a letra “g” dentro) e selecione a opção “New Web Application Project...”. Feito isso, será apresentada a janela da Figura 11.
Em “Project Name”, especifique o nome usado para o projeto – neste caso, “Contas”, o mesmo nome que utilizamos como “Application Title” (título da aplicação) no registro do aplicativo no Google App Engine.
Em “Package Name”, não deixe de fornecer um nome para o pacote base das classes Java. Se você fornecer outro nome de pacote, diferente do indicado na Figura 11 (net.querino.gae.compras), lembre-se de posteriormente atualizar o seu código Java de acordo.
Importante: este nosso projeto não utilizará o GWT (Google Web Toolkit) – um conjunto de componentes para criação de aplicações Web também criado pelo Google. Portanto, desmarque a opção “Use Google Web Toolkit”. Clique em seguida em “Finish”.
Ao concluir esta etapa, um “esqueleto” de um projeto básico será criado. Este projeto já pode inclusive ser executado e visualizado pelo navegador, já possuindo uma página de abertura (index.html) e um servlet básico (ContasServlet.java), como pode ser visto na Figura 12.
Para executar e testar o projeto localmente, clique sobre ele (“Contas”) e em seguida no botão Run da barra de ferramentas do Eclipse. Um servidor local será iniciado, e a aplicação estará disponível no endereço: http://localhost:8888. Abrindo o endereço pelo navegador, será exibida a tela da Figura 13.
Clicando sobre o link “Contas”, o servlet “ContasServlet” será executado e a tradicional mensagem “Hello, world” será exibida. Neste momento, começaremos a implementar nossa aplicação “em cima” deste modelo. Mantenha a janela do navegador aberta para testar a aplicação posteriormente.
Programando a classe Conta
O primeiro passo é criar o nosso “modelo”. O modelo, dentro da arquitetura de desenvolvimento de software em camadas, abrange os dados utilizados pela aplicação. No nosso caso, portanto, criaremos uma classe denominada Conta, onde serão indicados os dados de uma conta.
Arquitetura de Desenvolvimento em Camadas: O padrão de desenvolvimento em camadas propõe que os componentes de um software sejam divididos em módulos (as “camadas”) funcionalmente distintos, mas relacionados entre si. Esta separação visa facilitar a modificação, ou até mesmo substituição, de um destes módulos, de maneira que isso não afete (ou afete o mínimo possível) os demais.
Um dos padrões de divisão em camadas mais utilizados é o MVC (Model-View-Controller). Neste esquema, o software é dividido em três campos: o modelo, responsável pelos dados e sua lógica; a visão, que define a aparência em relação ao usuário; e o controlador, responsável em fazer a comunicação entre a visão e o modelo, com base na forma como o usuário interage com o primeiro.
Como vimos anteriormente, a persistência dos objetos Conta (ou seja, seu armazenamento permanente no banco de dados) será feita com o framework JPA. Assim, o código Java para a classe já deve conter as “annotations” necessárias.
Para criar a classe, dentro da pasta src do projeto, clique com o botão direito do mouse sobre o nome do pacote, e em seguida selecione New > Class. Com isso, será exibida a janela de criação de uma nova classe (Figura 14).
Especifique em “Name” o nome da classe: Conta. As demais opções da tela devem ser mantidas nos seus valores padrão. Clique em Finish para criar o arquivo Conta.java.
Definiremos nesta classe os campos para os dados de uma conta e seus respectivos getters e setters. Deste modo, escreva o código da classe de acordo com a Listagem 1.
Listagem 1. Código da classe Conta.
package net.querino.gae.contas;
import java.util.Date;
import javax.persistence.*;
@Entity
public class Conta {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String descricao;
private double valor;
private Date vencimento;
private String linhadigitavel;
public Conta(String descricao, double valor, Date vencimento, String linhadigitavel) {
this.descricao = descricao;
this.valor = valor;
this.vencimento = vencimento;
this.linhadigitavel = linhadigitavel;
}
public Long getId() {
return id;
}
public String getDescricao() {
return descricao;
}
public void setDescricao(String descricao) {
this.descricao = descricao;
}
public double getValor() {
return valor;
}
public void setValor(double valor) {
this.valor = valor;
}
public Date getVencimento() {
return vencimento;
}
public void setVencimento(Date vencimento) {
this.vencimento = vencimento;
}
public String getLinhadigitavel() {
return linhadigitavel;
}
public void setLinhadigitavel(String linhadigitavel) {
this.linhadigitavel = linhadigitavel;
}
}
Após os necessários imports, a annotation @Entity declara que a classe será uma entidade JPA, passível de armazenamento persistente. Dentro da classe, são declarados os atributos necessários de uma conta. Atenção especial ao atributo “id” e às annotations colocadas sobre ele (@Id e @GeneratedValue). Elas indicam que o mesmo atuará como o campo identidade, ou “chave primária” no banco de dados, para garantir um código identificador único para cada conta.
Configurando a aplicação para usar JPA
Para que o App Engine “saiba” que a aplicação vai utilizar JPA, precisamos criar o arquivo persistence.xml dentro da pasta META-INF. Deste modo, clique com o botão direito do mouse sobre esta pasta e selecione New > File. Na janela que será exibida, especifique em “File name” o nome persistence.xml. O conteúdo do arquivo deve ser o indicado na Listagem 2.
Listagem 2. Arquivo persistence.xml.
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider
Trata-se de um arquivo XML contendo as configurações básicas para o uso de JPA na implementação utilizada pelo Google App Engine, denominada DataNucleus. Estas são as configurações recomendadas pelo Google no manual do App Engine, e são relativas à leitura e gravação de dados não-transacionais e à URL de conexão ao serviço. Caso você precise de alguma configuração específica para sua aplicação, consulte a documentação do App Engine.
Definindo um gerenciador para as entidades JPA
O gerenciamento das entidades é feito por uma classe denominada EntityManager. A criação de uma instância desta classe é feita por um EntityManagerFactory, e como esta é uma operação que leva um tempo para ser realizada, é uma boa ideia reutilizar uma única instância. Por isso, vamos criar uma classe denominada EMF com uma instância estática, ou seja, um singleton.
Singleton: O padrão de projeto (design pattern) Singleton é amplamente usado e difundido na Engenharia de Software, e serve para definir que apenas uma única instância (um mesmo objeto) possa ser obtida de uma classe. É particularmente útil quando um único objeto da classe é suficiente para a aplicação como um todo, eliminando a carga decorrente da criação contínua de instâncias desnecessárias.
Para tanto, clique com o botão direito sobre o nome do pacote, dentro da pasta src e selecione New > Class. Dê o nome EMF para a classe, clique em Finish e escreva o código de acordo com a Listagem 3.
Listagem 3. Código da classe EMF.
package net.querino.gae.contas;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
public final class EMF {
private static final EntityManagerFactory emfInstance =
Persistence.createEntityManagerFactory("transactions-optional");
private EMF() {}
public static EntityManagerFactory get() {
return emfInstance;
}
}
Este singleton será utilizado dentro da classe de acesso a dados, criada na próxima seção.
Criando a classe de acesso a dados
Vamos agora criar uma classe DAO (Data Access Object). A função desta classe é, utilizando o EntityManager obtido pela classe EMF, permitir a inclusão, exclusão e listagem das contas.
Assim, crie uma nova classe Java, agora com o nome Dao, e deixe-a de acordo com o código da Listagem 4.
Listagem 4. Código da classe Dao.
package net.querino.gae.contas;
import java.util.Date;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
public class Dao {
public void incluirConta(String descricao, double valor, Date vencimento, String linhaDigitavel){
EntityManager em = EMF.get().createEntityManager();
Conta conta = new Conta(descricao, valor, vencimento, linhaDigitavel);
em.persist(conta);
em.close();
}
public void excluirConta(long id) {
EntityManager em = EMF.get().createEntityManager();
try {
Conta conta = em.find(Conta.class, id);
em.remove(conta);
} finally {
em.close();
}
}
public List listarContas() {
EntityManager em = EMF.get().createEntityManager();
Query q = em.createQuery("select m from Conta m");
List contas = q.getResultList();
return contas;
}
}
Esta classe contém apenas três métodos:
1. incluirConta(): cria um objeto Conta com os valores recebidos como parâmetro e, utilizando o EntityManager, faz a persistência dos dados;
2. excluirConta(): recebe o identificador de uma conta como parâmetro, localiza a mesma e faz sua exclusão;
3. listarConta(): cria uma Query JPA com um comando de consulta que obtém todas as contas cadastradas, retornando-as como objetos Conta dentro de um List.
Servlet para criação e exclusão de contas
A página principal do aplicativo, que criaremos em JSP no próximo passo, vai trazer uma listagem das contas já cadastradas e um formulário para inclusão de uma nova conta.
Na listagem, quando o usuário clicar na coluna “Baixar conta”, a página irá enviar a um servlet uma solicitação GET, passando o código da conta a ser excluída. Consequentemente, precisamos implementar um servlet que atenda a esta finalidade, devendo possuir um método doGet() que recebe o código e realiza a exclusão, utilizando o método excluirConta() da classe Dao criada anteriormente.
Nesta mesma página JSP, quando o usuário preencher os dados do formulário relativo à criação de uma nova conta e clicar no botão “Incluir”, um servlet também deverá ser acionado, agora recebendo os dados da nova conta pelo método POST. Dessa forma, vamos implementar dentro deste servlet o método doPost(), que recebe os dados e realiza a “persistência” do objeto Conta, por meio de uma chamada ao método incluirConta() existente em Dao.
Para simplificar, vamos implementar estes métodos em um mesmo servlet (poderíamos, sem problema algum, criar um servlet para exclusão e outro para inclusão), aproveitando o exemplo criado automaticamente com o projeto (no arquivo denominado ContasServlet.java). Inicialmente, ele contém apenas a saída da mensagem “Hello, world” na tela. Vamos então modificá-lo, implementando os métodos doGet() e doPost() de acordo com o especificado. Pensando nisso, modifique o código de ContasServlet para que fique como na Listagem 5.
Listagem 5. Código da classe ContasServlet.
package net.querino.gae.contas;
import java.io.IOException;
import java.util.Date;
import java.text.*;
import javax.servlet.ServletException;
import javax.servlet.http.*;
@SuppressWarnings("serial")
public class ContasServlet extends HttpServlet {
private Dao dao;
private DateFormat formatadorData;
public void init() throws ServletException {
dao = new Dao();
formatadorData = new SimpleDateFormat("dd/MM/yyyy");
}
public void doPost(HttpServletRequest req, HttpServletResponse resp)throws IOException {
String descricao = req.getParameter("descricao");
if (descricao == null || descricao.trim().equals("")) {
descricao = "CONTA SEM DESCRIÇÃO";
}
double valor;
try {
valor = Double.parseDouble(req.getParameter("valor").replace(',', '.'));
} catch (NumberFormatException ex) {
valor = 0;
}
Date vencimento;
try {
vencimento = formatadorData.parse(req.getParameter("vencimento"));
} catch (ParseException ex) {
vencimento = new Date();
}
String linhaDigitavel = req.getParameter("linhaDigitavel");
if (linhaDigitavel == null || linhaDigitavel.trim().equals("")) {
linhaDigitavel = "NÃO INFORMADA";
}
dao.incluirConta(descricao, valor, vencimento, linhaDigitavel);
resp.sendRedirect("/Contas.jsp");
}
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String id = req.getParameter("id");
dao.excluirConta(Long.valueOf(id));
resp.sendRedirect("/Contas.jsp");
}
}
Voltando ao método doPost(), note que algumas validações simples são realizadas, de modo que valores nulos ou em branco possam ser substituídos e não ocasionem erros. Obviamente, estas validações podem posteriormente ser implementadas diretamente no formulário de entrada dos dados da conta. No entanto, isto não faz parte do escopo deste artigo.
Ao final de cada método, o usuário é redirecionado à página principal da aplicação (Contas.jsp), por meio do método sendRedirect().
Página JSP da aplicação
Neste momento, definiremos o arquivo JSP, responsável pelo “rosto” da aplicação Web. Para tanto, clique com o botão direito do mouse sobre a pasta war do projeto e selecione New > Other. Na janela que será exibida, selecione Web > JSP File. Feito isso, será mostrada uma tela onde deve ser definido um nome para o arquivo. Assim, em “File Name”, informe Contas.jsp e clique em Finish. Será criado um arquivo JSP básico. Modifique-o de acordo com a Listagem 6.
Listagem 6. Código do arquivo Contas.jsp.
Contas
Relação de contas
List contas = new ArrayList();
SimpleDateFormat formatadorData = new SimpleDateFormat("dd/MM/yyyy");
Dao dao = new Dao();
NumberFormat formatadorMoeda = NumberFormat.getCurrencyInstance(new Locale("pt","BR"));
contas = dao.listarContas();
%>
Descrição
Valor
Data de Vencimento
Linha Digitável do Código de Barras
Dar baixa
...