Oracle Mobile Application Framework 2.0: Usando Banco de Dados Local

Por Waslley Souza
Postado em Janeiro 2015


Quando você está construindo uma aplicação MAF, você pode decidir usar Web Services (SOAP / REST) ou banco de dados local para recuperar ou persistir seus dados. Se você decidir usar o banco de dados local, o SQLite é o banco de dados padrão do MAF. SQLite é projetado para ser usado como um sistema de banco de dados integrado, normalmente usado por um único usuário e muitas vezes ligado diretamente no aplicativo. Ele é ACID-compliant, leve e portátil.

Neste artigo vou criar um CRUD de funcionários no Oracle MAF 2.0 usando banco de dados SQLite. Baixe o aplicativo de exemplo: MAFDBApp.zip.

Crie um Application Framework Mobile Application, e nomeie como MAFDBApp.

 


No arquivo maf-feature.xml, crie uma nova feature e nomeie como employees


Clique na guia Content e, em seguida, clique no botão mais verde perto do campo File, para criar o EmployeesTF Task Flow


Crie o arquivo initializedb.sql.
Este script SQL inicializa o banco de dados quando o aplicativo é iniciado.
Vá ao painel Projects > projeto ApplicationController, clique com o botão direito na pasta META-INF e selecione New > From Gallery.
Na caixa de diálogo New Gallery, escolha General > File. 

Copie o código a seguir no arquivo. 

PRAGMA auto_vacuum = FULL;
CREATE TABLE EMPLOYEES (EMPLOYEE_ID NUMBER(6) PRIMARY  KEY, FIRST_NAME VARCHAR2(20), LAST_NAME VARCHAR2(25) 
NOT NULL, EMAIL  VARCHAR2(25) NOT NULL);
INSERT INTO EMPLOYEES (EMPLOYEE_ID, FIRST_NAME,  LAST_NAME, EMAIL) 
VALUES (100,'David','King','steven@king.net');
INSERT INTO EMPLOYEES (EMPLOYEE_ID, FIRST_NAME,  LAST_NAME, EMAIL) 
VALUES (101,'Neena','Kochhar','neena@kochhar.net');
INSERT INTO EMPLOYEES (EMPLOYEE_ID, FIRST_NAME,  LAST_NAME, EMAIL) 
VALUES (102,'Lex','De Haan','lex@dehaan.net');
INSERT INTO EMPLOYEES (EMPLOYEE_ID, FIRST_NAME,  LAST_NAME, EMAIL) 
VALUES (103,'Alexander','Hunold','alexander@hunold.net');
INSERT INTO EMPLOYEES (EMPLOYEE_ID, FIRST_NAME,  LAST_NAME, EMAIL) 
VALUES (104,'Bruce','Ernst','bruce@ernst.net');

 

Abra o arquivo LifeCycleListenerImpl.java.
Substitua o método start() pelo seguinte código: 

public void start() { 
try { 
initializeDatabaseFromScript(); 
} catch (Exception e) { 
Trace.log(Utility.ApplicationLogger,  Level.SEVERE, this.getClass(), "start", e); 
}
}

 

Adicione o método initializeDatabaseFromScript().
Este método cria o banco de dados e executa as instruções SQL. 

private void initializeDatabaseFromScript() throws  Exception { 
InputStream scriptStream = null; 
Connection conn = null;

try { 
// ApplicationDirectory returns the  private read-write sandbox area 
// of the mobile device's file system  that this application can access. 
// This is where the database is  created 
String docRoot =  AdfmfJavaUtilities.getDirectoryPathRoot(AdfmfJavaUtilities.ApplicationDirectory); 
String dbName = docRoot +  "/sample.db";

// Verify whether or not the database  exists. 
// If it does, then it has already  been initialized 
// and no furher actions are required 
File dbFile = new File(dbName); 
if (dbFile.exists()) 
return;

// If the database does not exist, a  new database is automatically 
// created when the SQLite JDBC  connection is created 
conn = new  SQLite.JDBCDataSource("jdbc:sqlite:" + docRoot +  "/sample.db").getConnection();

// To improve performance, the  statements are executed 
// one at a time in the context of a  single transaction 
conn.setAutoCommit(false);

// Since the SQL script has been  packaged as a resource within 
// the application, the  getResourceAsStream method is used 
scriptStream =  Thread.currentThread().getContextClassLoader().getResourceAsStream("META-INF/initializedb.sql"); 
BufferedReader scriptReader = new  BufferedReader(new InputStreamReader(scriptStream)); 
String nextLine; 
StringBuffer nextStatement = new  StringBuffer();

// The while loop iterates over all  the lines in the SQL script, 
// assembling them into valid SQL  statements and executing them as 
// a terminating semicolon is  encountered 
Statement stmt =  conn.createStatement(); 
while ((nextLine =  scriptReader.readLine()) != null) { 
// Skipping blank lines, comments, and  COMMIT statements 
if  (nextLine.startsWith("REM") ||  nextLine.startsWith("COMMIT") || nextLine.length() < 1) { 
continue; 
}

nextStatement.append(nextLine);

if (nextLine.endsWith(";"))  { 
stmt.execute(nextStatement.toString()); 
nextStatement = new  StringBuffer(); 
} 
}

conn.commit();

} finally { 
if (conn != null) { 
conn.close(); 
} 
}
}

 

Crie a classe DBConnectionFactory.
Esta classe gerencia as conexões de banco de dados.
Vá ao painel Projects, clique com o botão direito no projeto ApplicationController e selecione New > Java Class. 


Substitua todo o conteúdo do arquivo com o seguinte código: 

package br.com.waslleysouza.application;

import java.sql.Connection;
import java.sql.SQLException;

import oracle.adfmf.framework.api.AdfmfJavaUtilities;
import oracle.adfmf.util.Utility;

public class DBConnectionFactory { 
private static Connection conn = null;

public DBConnectionFactory() { 
super(); 
}

public static Connection  getConnection() throws Exception { 
if (conn == null) { 
try { 
String dirRoot =  AdfmfJavaUtilities.getDirectoryPathRoot(AdfmfJavaUtilities.ApplicationDirectory); 
String connStr =  "jdbc:sqlite:" + dirRoot + "/sample.db"; 
conn = new  SQLite.JDBCDataSource(connStr).getConnection(); 


} catch (SQLException e) { 
Utility.ApplicationLogger.severe(e.getMessage()); 
} 
}
return conn; 
}

public static void closeConnection() { 
try { 
if (conn != null) { 
conn.close(); 
conn = null; 
} 
} catch (Exception ex) { 
throw new RuntimeException(ex); 
} 
}
}

 

Vá ao painel Projects, clique duas vezes no projeto ViewController e escolha Dependencies.
Adicione o projeto ApplicationController como dependência. 


Crie a entidade Employee.
Vá ao painel Projects, clique com o botão direito no projeto ViewController e selecione New > Java Class.
Nesta aplicação, a classe Employee deve implementar a classe Cloneable. 


Substitua todo o conteúdo do arquivo com o seguinte código: 

package br.com.waslleysouza.mobile;

public class Employee implements Cloneable { 
private Integer employeeId; 
private String firstName; 
private String lastName; 
private String email;

public Employee() { 
super(); 
}

protected Object clone() throws  CloneNotSupportedException { 
return super.clone(); 
}
}

 

Gere os assessores.
Marque esta opção: “Notify listeners when property changes”. 

 

Crie a classe DBAdapter.
Esta classe contém códigos para recuperar / persistir dados em banco de dados.
Vá ao painel Projects, clique com o botão direito no projeto ViewController e selecione New > Java Class. 


Substitua todo o conteúdo do arquivo com o seguinte código: 

package br.com.waslleysouza.mobile;

import  br.com.waslleysouza.application.DBConnectionFactory;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import oracle.adfmf.util.Utility;

public class DBAdapter { 
public DBAdapter() { 
super(); 
}

protected boolean executeUpdate(String  query) { 
boolean success = false;

try { 
Connection conn =  DBConnectionFactory.getConnection(); 
Statement stmt =  conn.createStatement(); 
int rowCount =  stmt.executeUpdate(query);

if (rowCount > 0) { 
success = true; 
Utility.ApplicationLogger.severe("RowCount="  + rowCount + ", Query=" + query); 
}

} catch (Exception e) { 
Utility.ApplicationLogger.severe(e.getMessage()); 
e.printStackTrace(); 
throw new RuntimeException(e);

} finally { 
DBConnectionFactory.closeConnection(); 
}

return success; 
}

protected ResultSet  executeQuery(String query) { 
ResultSet result = null;

try { 
Connection conn =  DBConnectionFactory.getConnection(); 
Statement stmt =  conn.createStatement(); 
result = stmt.executeQuery(query);

} catch (Exception ex) { 
Utility.ApplicationLogger.severe(ex.getMessage()); 
ex.printStackTrace(); 
throw new RuntimeException(ex);

} finally { 
DBConnectionFactory.closeConnection(); 
}

return result; 
}
}

 

Crie a classe EmployeeAdapter.
Esta classe contém códigos para recuperar / persistir funcionários em banco de dados.
Vá ao painel Projects, clique com o botão direito no projeto ViewController e selecione New > Java Class. 


Substitua todo o conteúdo do arquivo com o seguinte código: 

package br.com.waslleysouza.mobile;

import java.sql.ResultSet;

import java.util.ArrayList;
import java.util.List;

import oracle.adfmf.util.Utility;

public class EmployeeAdapter extends DBAdapter { 
public EmployeeAdapter() { 
super(); 
}

public List findAllEmployees() { 
List employees = new ArrayList();

try { 
ResultSet result =  executeQuery("SELECT EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL FROM  EMPLOYEES;");

while (result.next()) { 
Employee  employee = new Employee(); 
employee.setEmployeeId(new  Integer(result.getInt("EMPLOYEE_ID"))); 
employee.setFirstName(result.getString("FIRST_NAME")); 
employee.setLastName(result.getString("LAST_NAME")); 
employee.setEmail(result.getString("EMAIL")); 
employees.add(employee); 
Utility.ApplicationLogger.severe("Employee:  " + employee.getEmployeeId() + "," + 
employee.getFirstName()  + "," + employee.getLastName() + "," + 
employee.getEmail()); 
}

} catch (Exception ex) { 
Utility.ApplicationLogger.severe(ex.getMessage()); 
ex.printStackTrace(); 
throw new RuntimeException(ex); 
}

return employees; 
}

public boolean insertEmployee(Employee  employee) { 
return executeUpdate("INSERT INTO  EMPLOYEES (EMPLOYEE_ID, FIRST_NAME, LAST_NAME, EMAIL) VALUES (" + 
employee.getEmployeeId()  + ",'" + employee.getFirstName() + "','" + 
employee.getLastName()  + "','" + employee.getEmail() + "')"); 
}

public boolean deleteEmployee(Integer  id) { 
return executeUpdate("DELETE FROM  EMPLOYEES WHERE EMPLOYEE_ID=" + id); 
}

public boolean updateEmployee(Employee  employee) { 
return executeUpdate("UPDATE  EMPLOYEES SET FIRST_NAME='" + employee.getFirstName() + "',  LAST_NAME='" + 
employee.getLastName()  + "', EMAIL='" + employee.getEmail() + "' WHERE  EMPLOYEE_ID=" + 
employee.getEmployeeId()); 
}
}

 

Crie a classe EmployeeDC.
Essa classe usa os métodos da classe EmployeeAdapter.
Vá ao painel Projects, clique com o botão direito no projeto ViewController e selecione New > Java Class. 


Substitua todo o conteúdo do arquivo com o seguinte código: 

package br.com.waslleysouza.mobile;

import java.util.ArrayList;
import java.util.List;

public class EmployeeDC { 
private Employee employee; 
private List employees = new  ArrayList(); 
private EmployeeAdapter adapter = new  EmployeeAdapter();

public EmployeeDC() { 
super(); 
findAll(); 
}

public void setEmployee(Employee  employee) { 
this.employee = employee; 
}

public Employee getEmployee() { 
return employee; 
}

public Employee[] getEmployees() { 
return (Employee[])  employees.toArray(new Employee[employees.size()]); 
}

public void findAll() { 
employees =  adapter.findAllEmployees(); 
}

public void delete(Integer employeeId)  { 
boolean success =  adapter.deleteEmployee(employeeId); 
if (success) { 
employees.remove(employee); 
} 
}

public void insert(Employee employee)  { 
boolean success =  adapter.insertEmployee(employee); 
if (success) { 
employees.add(employee); 
} 
}

public void update(Employee employee)  { 
boolean success =  adapter.updateEmployee(employee); 
if (success) { 
int index =  employees.indexOf(employee); 
employees.set(index, employee); 
} 
}

public void prepareEmployeeToAdd() { 
employee = new Employee(); 
}

public void  prepareEmployeeToEdit(Employee employee) throws CloneNotSupportedException { 
this.employee = (Employee)  employee.clone(); 
}
}

 

Crie o EmployeeDC Data Control.
Vá ao painel Projects, clique com o botão direito no arquivo EmployeeDC.java e escolha Create Data Control.
Na caixa de diálogo Create Bean Data Control, clique em Next e em Finish

 


Abra o arquivo EmployeesTF.xml.
Vá para o painel Components, arraste três componentes View e um Wildcard Control Flow Rule e solte dentro da EmployeesTF.
Conecte-os usando o componente Flow Control Case. 


Clique duas vezes em todos os componentes View e clique em OK para criar as AMX Pages


Abra a página employeeList.
Vá ao painel Data Control, arraste a coleção employees e solte dentro da página como MAF List View.
Na ListView Gallery, clique em OK duas vezes. 

 

No componente listItem, defina a propriedade: action="toEmployeeDetail".
No componente outputText, defina a propriedade: value="#{row.lastName}, #{row.firstName}".

Remova o componente commandButton do facet secondary.

Vá ao painel Data Controls > EmployeeDC, arraste a operação prepareEmployeeToAdd e solte dentro do facet secondary como MAF Button.
Defina as propriedades: text="Add" e action="toEditEmployee".
Vá ao painel Components > Operations, arraste o componente Set Property Listener e solte dentro do componente commandButton.
Defina as propriedades: from="#{'add'}" e to="#{pageFlowScope.actionSelected}"


Vá para Bindings e edite o employees binding.
Adicione lastName e firstName como Display Attributes

 

Abra a página employeeDetail.
Vá ao painel Data Control, arraste a coleção employees e solte dentro da página como MAF Read-only Form.
Na caixa de diálogo Edit Form Fields, clique em Ok

 

Remova o componente commandButton do facet secondary.

Vá ao painel Data Control, arraste a operação delete(Integer) e solte dentro do facet secondary como Method > MAF Button.
Em Edit Action Binding, defina o valor de employeeId para #{bindings.employeeId.inputValue}

 

Defina as propriedades: text="Delete" e action="toEmployeeList".

No componente commandButton do facet primary, defina as propriedades: text="Back" e action="__back".

Vá ao painel Data Control, arraste a operação prepareEmployeeToEdit(Employee) e solte dentro do facet secondary como MAF Button.
Em Edit Action Binding, defina o valor de employee para #{bindings.employeesIterator.currentRow.dataProvider}

Defina as propriedades: text="Edit" e action="toEditEmployee".
Vá ao painel Components > Operations, arraste o componente Set Property Listener e solte dentro do componente commandButton.
Defina as propriedades: from="#{'edit'}" e to="#{pageFlowScope.actionSelected}"


Abra a página editEmployee.
Adicione o componente Validation Group para validar campos obrigatórios.
Vá ao painel Components > Operations, arraste o componente Validation Group e solte dentro da página.
Defina a propriedade: id="vg1".

Vá ao painel Data Control, arraste o atributo estruturado employee e solte dentro do componente validationGroup como MAF Form.
Na caixa de diálogo Edit Form Fields, clique em Ok

 

No componente commandButton do facet primary, defina as propriedades: text="Back" e action="__back".

Remova o componente commandButton do facet secondary.

Vá ao painel Data Control, arraste a operação insert(Employee) e solte dentro do facet secondary como MAF Button.
Em Edit Action Binding, defina o valor de employee para #{bindings.employeeIterator.currentRow.dataProvider}


Defina as propriedades: text="Save", action="toEmployeeList" e rendered="#{pageFlowScope.actionSelected == 'add'}".
Vá ao painel Components > Operations, arraste o componente Validation Behavior e solte dentro do componente commandButton.
Defina a propriedade: group="vg1".

Vá ao painel Data Control, arraste a operação update(Employee) e solte dentro do facet secondary como MAF Button.
Em Edit Action Binding, defina o valor de employee para #{bindings.employeeIterator.currentRow.dataProvider}


Defina as propriedades: text="Update", action="toEmployeeList" e rendered="#{pageFlowScope.actionSelected == 'edit'}".
Vá ao painel Components > Operations, arraste o componente Validation Behavior e solte dentro do componente commandButton.
Defina a propriedade: group="vg1".

Para todos os componentes InputText, defina as propriedades: required="true" e showRequired="true". 


Faça deploy do aplicativo e divirta-se! 

 

Referência:
https://docs.oracle.com/middleware/mobile201/mobile/develop/maf-sqlite-db.htm



Waslley Souza é Oracle ACE Associate e Consultor Oracle com foco em tecnologias Oracle Fusion Middleware e SOA. Pós-graduado em Engenharia de Software (SOA) e bacharel em Ciências da Computação. Certificado Oracle WebCenter Portal, Oracle ADF e Java. Escreve frequentemente em seu blog: http://waslleysouza.com.br.

Este artigo foi revisto pela equipe de produtos Oracle e está em conformidade com as normas e práticas para o uso de produtos Oracle.