Conteúdo


Desenvolver um aplicativo Java EE portátil em padrões Bluemix e de nuvem particular

Preservando a promessa “escrever uma vez, executar em qualquer lugar” do Java entre ambientes de nuvem

Comments

Como desenvolvedor Java, você espera a promessa de “escrever uma vez, executar em qualquer lugar” dessa linguagem. Como garantir isso se você está movendo aplicativos entre o IBM Bluemix e ambientes de nuvem no local, como o SmartCloud Orchestrator ou o PureApplication System?

À medida que você usa diferentes plataformas de implementação, o código do aplicativo pode, inadvertidamente, passar a depender da plataforma, eliminando a proposta de valor de "executar em qualquer lugar". Neste tutorial, contamos como nós resolvemos as diferenças em conectividade e inicialização de banco de dados entre os dois ambientes. São incluídos o código do aplicativo e o código de automação de implementação e de inicialização de banco de dados.

Mostraremos como escrever um aplicativo Java EE que pode ser implementado sem problemas no Bluemix e, usando o Web Application Pattern, no SmartCloud Orchestrator.

Vamos primeiro observar o código para ver as diferenças na conectividade do banco de dados entre as plataformas e como nós implementamos uma solução portátil. Em seguida, explicaremos a automação da implementação e como empacotar o aplicativo para implementar nas duas plataformas. Por último, trataremos do desafio de inicializar o banco de dados no Bluemix sem afetar a portabilidade de aplicativos.

Execute o aplicativoObtenha o código

O que será necessário para desenvolver o aplicativo

  • Uma conta do Bluemix
  • Uma conta do DevOps Services
  • Familiaridade com Java EE
  • Acesso a uma instância do SmartCloud Orchestrator ou do PureApplication

Etapa 1. Entender a amostra de aplicativo Java EE

  • Design: Nosso aplicativo de amostra exibe uma lista de faturas. O design segue o padrão Model View Controller (MVC). Um servlet Java chama a camada de acesso aos dados para obter uma lista de faturas e, em seguida, repassa a lista à camada de apresentação que, por sua vez, aplica regras de formatação aos dados e renderiza uma página da web.
  • Código: Clique no botão Obtenha o código acima para visualizar o código fonte em um projeto do DevOps Services. Se quiser fazer alterações no código, clique no botão EDIT CODE.
    EDIT CODE button in DevOps         Services
    EDIT CODE button in DevOps Services

    E, em seguida, clique em FORK no projeto DevOps Service para criar sua própria cópia: FORK button in DevOps Services
    FORK button in DevOps Services

    Ou faça o download para o sistema de arquivos local usando o item de menu File > Export e modifique com seu editor favorito: File > Export menu in DevOps         services
    File > Export menu in DevOps services
  • Estrutura do banco de dados: Nosso banco de dados é muito simples: um esquema que contém uma tabela para representar faturas. Aqui está uma parte de SampleDatabase.sql:
    CREATE SCHEMA DEMO;
    
    CREATE TABLE DEMO.INVOICES (
    	INVOICE_ID INTEGER NOT NULL,
    	CUSTOMER_NAME VARCHAR(100),
    	SHIPPING_ADDRESS VARCHAR(250),
    	AMOUNT DOUBLE
    );
    
    ALTER TABLE DEMO.INVOICES ADD PRIMARY KEY (INVOICE_ID);
    
    INSERT INTO DEMO.INVOICES (INVOICE_ID, CUSTOMER_NAME, SHIPPING_ADDRESS, AMOUNT)
         VALUES ( 11222, 'Marco De Santis', 'Via Sciangai 53 000144 Rome Italy', 100.0);
    INSERT INTO DEMO.INVOICES (INVOICE_ID, CUSTOMER_NAME, SHIPPING_ADDRESS, AMOUNT)
         VALUES ( 11223, 'Ruth Willenborg', '3901 S MIAMI BLVD DURHAM , NC , 27703-9135  United States', 1000.0);
  • Modelo: Para modelar nosso objeto Invoice, um simples POJO em src/com/ibm/vapps/model/Invoice.java contém alguns campos, um construtor e métodos getter/setter:
    public class Invoice {	
    	private int id;	
    	private String customerName;	
    	private String shippingAddress;	
    	private double amount;	
    	...
    }
  • Controlador: O servlet recupera dados do Data Access Object (DAO) e encaminha para a camada de apresentação:
    private static final String INVOICES_JSP_PAGE = "invoices.jsp";
    
    protected void doGet(HttpServletRequest request,
    			HttpServletResponse response) throws ServletException, IOException {
    		List<Invoice> invoices = new ArrayList<Invoice>();
    		try {
    			invoices = InvoicesDAO.retrieveInvoices();
    		} catch (DatabaseException e) {
    			request.setAttribute(ERROR_ATTRIBUTE_NAME,
    					ErrorMessages.ERROR_RETRIEVING_DATA_MESSAGE);
    		}
    		request.setAttribute(INVOICES_ATTRIBUTE_NAME, invoices);
    		RequestDispatcher rd = getServletContext().getRequestDispatcher(
    				INVOICES_JSP_PAGE);
    		rd.forward(request, response);
    	}
  • Visualização: A camada de visualização é implementada através de uma página JSP, que exibe os detalhes da fatura em uma tabela HTML com estilização:
    	<table>
    		<thead>
    			<tr>
    				<th>Invoice Id</th>
    				<th>Customer Name</th>
    				<th>Shipping Address</th>
    				<th>Amount</th>
    			</tr>
    		</thead>
    		<tbody>		
    		<%
    			List<Invoice> invoices = (List<Invoice>)request.getAttribute("invoices");
    			for (Iterator<Invoice> iter = invoices.iterator(); iter.hasNext();) {
    				Invoice invoice = iter.next();
    		%>
    		<tr>
    				<td><%=invoice.getId()%></td>
    				<td><%=invoice.getCustomerName()%></td>
    				<td><%=invoice.getShippingAddress()%></td>
    				</tr>
    		<%
    			}
    		%>
    		</tbody>
    	</table>

O código completo está disponível em WebContent/invoices.jsp no projeto DevOps Services.

Etapa 2. Entender as plataformas de implementação

Para entregar nosso aplicativo Java EE, precisamos de três coisas: um contêiner Java EE, um DBMS e uma configuração JDBC para auxiliar na comunicação. Vejamos o que as infraestruturas de implementação oferecem e como usá-las para realizar nossa tarefa.

  • No SmartCloud Orchestrator e no PureApplication, usaremos Virtual Application (VApp) Patterns para definir um modelo implementável do nosso aplicativo. Usando a Application Builder User Interface, podemos definir a topologia lógica usando nós e conectando-os uns aos outros. No nosso caso, o VApp ficará assim:
    Screenshot of the IBM SmartCloud     Orchestrator - Virtual Application Builder
    Screenshot of the IBM SmartCloud Orchestrator - Virtual Application Builder
    1. O nó Enterprise Application representa uma instância clássica do WebSphere e exige o upload de um arquivo EAR como parâmetro de configuração.
    2. O nó Database representa uma instância do DB2 e exige o upload de um script SQL como parâmetro de configuração.
    3. A connection entre eles representa a configuração JDBC e exige o nome JNDI da fonte de dados como parâmetro de configuração.
  • Ao criar um aplicativo novo no Bluemix, podemos escolher entre um amplo conjunto de tempos de execução de middleware.
    1. WebSphere Liberty for Java é adequado para nosso servidor de aplicativos. Usando a CLI, é possível realizar o push de um archive de perfil de servidor de aplicativos inteiro, integrando ao EAR.
    2. O serviço SQL Database implementará a camada de persistência. Os serviços devem ser vinculados a aplicativos, portanto, essa é a ligação entre o servidor de aplicativos e o banco de dados. Isso possibilita automaticamente a comunicação entre os aplicativos de middleware, enviando a configuração para uma variável de ambiente chamada VCAP_SERVICES. Isso é padrão no Bluemix.
    Bluemix dashboard showing the     Liberty for Java runtime and SQL Database service added
    Bluemix dashboard showing the Liberty for Java runtime and SQL Database service added

Etapa 3. Entender como acessar serviços

Embora pareça que as duas plataformas oferecem os mesmos recursos, existem diferenças sutis entre as configurações de comunicação do servidor de aplicativos e do banco de dados. Com o SmartCloud Orchestrator/PureApplication VApp, é solicitado explicitamente ao usuário que forneça um nome JNDI para consultar a fonte de dados, o que difere da abordagem com VCAP_SERVICES do Bluemix.

Analisando a fundo a documentação do serviço SQL Database do Bluemix, você verá que existe algo a mais. O recurso de autoconfiguração do JDBC cria um recurso JNDI chamado /jdbc/<ServiceInstanceName> e o disponibiliza ao Liberty.

Usando o padrão Virtual Application no SmartCloud, o Orchestrator impõe o uso do padrão JNDI para recuperar a fonte de dados. No entanto, também é necessário inserir no código o nome JNDI para consulta no aplicativo, como descreve a documentação:

"Supõe-se que o aplicativo use configurações do Java Naming and Directory Interface (JNDI) para localizar a fonte de dados. Especifique o nome JNDI no painel de propriedades de vinculação. Durante a implementação, o nome JNDI é configurado para a fonte de dados correspondente e deve ser igual ao nome no código do aplicativo."

O Bluemix suporta tanto a configuração de conexão ao banco de dados em uma variável VCAP_SERVICES, como um nome JNDI para consulta. Para evitar que nosso código dependa de VCAP_SERVICES do Bluemix, optamos pelo padrão JNDI do Java EE.

Para que nosso aplicativo continue sendo portátil, colocamos no código do DAO um nome JNDI bem conhecido de acordo com as restrições do SmartCloud Orchestrator e damos à instância do SQL Database um nome correspondente no lado do Bluemix.

Dessa forma o src/com/ibm/vapps/dao/InvoicesDAO.java ficará assim:

public class InvoicesDAO {
						
	private static final String DATASOURCE_JNDI_NAME = "jdbc/DemoDataSource";	
	
	private static Connection getJNDIConnection() throws NamingException, SQLException {
		Context initialContext = new InitialContext();			
		DataSource datasource = (DataSource) initialContext.lookup(DATASOURCE_JNDI_NAME);		
		return datasource.getConnection();		
	}
	
	public static List<Invoice> retrieveInvoices() throws DatabaseException {
		...
	}
}

Etapa 4. Empacotar seu aplicativo

  1. Siga as normas do Java EE para empacotar arquivos EAR de aplicativos corporativos (<filename.ear>).
  2. O banco de dados é distribuído como um arquivo SQL contendo as declarações de Database Definition Language e alguns dados de amostra (<filename.sql>).
  3. No geral, nosso aplicativo é composto pelo archive EAR e o arquivo SQL.

Etapa 5. Implementar no Bluemix e testar

  1. Com a CLI do Cloud Foundry, é possível realizar o push de arquivos WAR diretamente, mas não de arquivos EAR. Para poder executar um arquivo EAR no tempo de execução Liberty, é necessário que seja um servidor compactado. Siga estas etapas para desenvolver o seu:
    1. Extraia o modelo fornecido, wlp.zip.
    2. Renomeie o arquivo EAR para bluemix.ear.
    3. Copie o arquivo EAR renomeado para o diretório wlp/usr/servers/libertyProfileServer/apps, sobrescrevendo o item temporário existente.
    4. Reempacote a estrutura de diretório como um archive zip, por exemplo, server.zip.
    5. Execute o comando a seguir:
      cf push server.zip
  2. Vincule um serviço SQL Database ao novo aplicativo. O nome da instância deve corresponder ao recurso JNDI. Chamamos nossa instância de serviço DemoDataSource, pois nosso aplicativo deve consultar a cadeia de caracteres jdbc/DemoDataSource. O recurso de autoconfiguração criará automaticamente um recurso JNDI no contêiner, chamado jdbc/<service_name>.
  3. Abra o aplicativo de gerenciamento da instância do SQL Database e carregue o arquivo SQL para inicializar o banco de dados usando o script SQL fornecido.Initalizing the SQL Database     instance
    Initalizing the SQL Database instance
  4. Acesse o aplicativo através da URL fornecida pelo Bluemix. Accessing the application
    Accessing the application

Etapa 6. Implementar no SmartCloud Orchestrator e testar

  1. Para começar, selecione Images&Pattern > Virtual Application Patterns no menu principal. Para criar um novo, clique no sinal verde de mais. Green plus sign
  2. Arraste um nó Enterprise Application da paleta à esquerda para a tela. Use o painel de configuração à direita para fazer upload do arquivo EAR. Uploading the EAR file
    Uploading the EAR file
  3. Faça o mesmo com o nó DB2 Database e faça upload do arquivo de esquema. Uploading the schema file
    Uploading the schema file
  4. Conecte os nós desenhando uma seta do aplicativo para o banco de dados. Dê à configuração o mesmo nome JNDI, jdbc/DemoDataSource. Clique em Deploy. Connecting the nodes
    Connecting the nodes
  5. Quando o processo de implementação terminar, o mesmo aplicativo que implementamos anteriormente estará em execução na nuvem privada.The running application
    The running application

Etapa 7. Automatizar a implementação com o SmartCloud Orchestrator

É possível automatizar ambos os fluxos descritos acima com o SmartCloud Orchestrator Content Pack para aplicativos da web. Após instalar o software e suas dependências no diretório SmartCloudOrchestrator, você encontrará ofertas no Catálogo Self Service para implementar o aplicativo Java EE no SmartCloud Orchestrator ou no Bluemix. Vejamos o exemplo do Bluemix.

  1. Selecione a oferta no catálogo Self-Service: Selecting the 'Deploy Java EE             Web Application to Bluemix' offering in the IBM SmartCloud Orchestrator             Self-Service catalog
    Selecting the 'Deploy Java EE Web Application to Bluemix' offering in the IBM SmartCloud Orchestrator Self-Service catalog
    Selecting the Java Enterprise        archive
    Selecting the Java Enterprise archive
  2. Faça upload do script SQL: Uploading the SQL script
    Uploading the SQL script
    Deploying the Java EE application
    Deploying the Java EE application

    Quando alguém clica no botão OK, é acionado um processo de negócios do SmartCloud Orchestrator que contata o Bluemix e realiza as mesmas operações que você realizou manualmente na Etapa 4.

Etapa 8. Inicializar o banco de dados

A automatização da inicialização do banco de dados é outra diferença entre o Bluemix e o padrão VApp do SmartCloud Orchestrator.

Nas etapas manuais do Bluemix, usamos uma interface com o usuário para administrar nosso banco de dados. No entanto, não existe maneira programática de realizar as mesmas operações. Além disso, por motivos de segurança, os serviços do Bluemix são executados em uma rede interna que não pode ser acessada pela Internet. Por isso, é impossível configurar um cliente SQL para conectar ao banco de dados hospedado.

A recomendação de melhores práticas do Bluemix é que o aplicativo contenha a lógica para preparar a estrutura do banco de dados. No entanto, como queremos que nosso aplicativo seja portátil, desenvolvemos uma solução alternativa usando um aplicativo auxiliar simples.

Para nossa solução automatizada, escrevemos um aplicativo Node.js com base no Node.js Cache Web Starter, fornecido pelo Bluemix. Esse código expõe um terminal HTTP que aceita solicitações POST que contenham um script SQL no corpo, que é executado em relação ao serviço destinado ao SQL Database. O aplicativo auxiliar tem tempo de vida curto, pois é usado apenas para entregar a solicitação POST que inicializa o banco de dados, sendo removido em seguida.

Para realizar o fluxo de inicialização, fazemos com que o SmartCloud Orchestrator controle um shell script que executa os seguintes comandos cf CLI:

  1. Efetue login com suas credenciais.
    cf login -a http://api.stage1.ng.bluemix.net -u ${USER} -p ${PASSWORD}
  2. Realize o push de um servidor Liberty empacotado, usando a opção –no-start para que o aplicativo não seja iniciado imediatamente.
    cf push ${APP_NAME} -p ${PACKED_SERVER}.zip --no-start
  3. Crie uma instância do serviço SQL DB.
    cf create-service sqldb sqldb_small ${JNDI_NAME}
  4. Vincule o serviço SQL DB ao aplicativo Liberty.
    cf bind-service ${APP_NAME} ${JNDI_NAME}
  5. Realize o push do aplicativo auxiliar.
    cf push ${APP_NAME}_dbinit  -c "node app.js" -p $WORK_DIR/dbinit.zip –no-start
  6. Vincule à mesma instância do serviço SQL DB.
    cf bind-service ${APP_NAME}_dbinit ${JNDI_NAME}
  7. Inicie o aplicativo auxiliar.
    cf start ${APP_NAME}_dbinit
  8. Realize um POST HTTP enviando as instruções SQL a serem executadas no banco de dados.
    curl -i -X POST -H "Content-Type: application/x-www-form-urlencoded" --data "@${SQL_FILE}{APP_NAME}" http://${APP_NAME}-dbinit.stage1.mybluemix.net/runSQLScript
  9. Desvincule o aplicativo auxiliar da instância do serviço SQL DB.
    cf unbind-service ${APP_NAME}_dbinit ${JNDI_NAME}
  10. Remova o aplicativo auxiliar do espaço Bluemix.
    cf d -f ${APP_NAME}_dbinit
  11. Inicie o aplicativo Liberty.
    cf start ${APP_NAME}

No SmartCloud Orchestrator, o banco de dados é inicializado automaticamente pelo Pattern Engine que processa o script fornecido como entrada. Quando a instância do DB2 iniciar, o banco de dados estará inicializado.

Conclusão

Atendo-se às normas de Java EE, a promessa do Java de "escrever uma vez, executar em qualquer lugar" permanece intacta através do IBM Bluemix e de padrões de aplicativo virtual no local. Neste tutorial, você viu as diferenças em termos de conectividade de banco de dados e como usar o JNDI para manter o código móvel. Você também viu uma técnica para automatizar a inicialização de banco de dados do Bluemix sem codificá-la no aplicativo. Com apenas um pouco de esforço, é possível manter a independência do aplicativo em relação à plataforma em que é implementado.

Agradecimentos

Gostaríamos de agradecer a equipe que trabalha conosco na inicialização de banco de dados do Bluemix:

Claudio Marinelli

Gianluca Bernardini

Paolo Ottaviano


Recursos para download


Temas relacionados


Comentários

Acesse ou registre-se para adicionar e acompanhar os comentários.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Tecnologia Java, Cloud computing
ArticleID=993892
ArticleTitle=Desenvolver um aplicativo Java EE portátil em padrões Bluemix e de nuvem particular
publish-date=12262014