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!
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.