Building an ADF Mobile CRUD Application Using Mobile Persistence Sample Code

streakgrowlInternet και Εφαρμογές Web

12 Νοε 2013 (πριν από 8 χρόνια και 2 μήνες)

529 εμφανίσεις

Building an ADF Mobile CRUD Application Using
Mobile Persistence Sample Code

Author: Steven Davelaar, Oracle ADF/WebCenter A-team
Date: 11 october 2013
1. Introduction
In this tutorial you will build an ADF Mobile application that allows you to query, insert, update and delete
departments. You will store the data both locally on your mobile device using a SQLite database , and
you will synchronize your local data with a remote server through RESTful web services.

As you will see, you can accomplish this with minimal Java coding because we will use sample code
created by the Oracle Fusion Middleware Architects team (“the A-team”) that accelerates your mobile
development. This accelerator code contains object-relational mapping functionality that allows you to
persist your domain object model to a local SQLite database as well as to a remote datasource. The
sample runtime library contains a number of local and remote persistence providers, and you can easily
plug in your own custom persistence provider if needed. To map your domain object model to database
tables, a mapping XML file is used. This mapping XML file is created by using a standard wizard available
in JDeveloper: “Create Java Objects from Tables”. This wizard creates the TopLink mapping XML file as
well as your domain objects. Note that apart from this XML file and the generated Java domain classes,
no TopLink libraries are used in the accelerator runtime code. The generated Java domain classes need
to be slightly modified to remove TopLink API-specific references like the ValueHolder interface.You will
use a utility that comes with this accelerator to do this.
The accelerator runtime library includes generic Java code to parse this mapping XML file, and construct
SQL SELECT, INSERT,UPDATE and DELETE statements from the domain object instance using the
mapping information. The concept of lazy loading (aka as indirection in TopLink/EclipseLink) is also
implemented. For example, the Department domain object has method getEmployees, the employees will
only be queried from the EMPLOYEES table in the database when this method is called for the first time.
An entity cache is also implemented to minimize domain object creation and to facilitate findByKey
methods.
If the mobile device is offline or the remote server is unavailable, the accelerator runtime will keep track of
any pending data synch actions that need to be synchronized later when the remote server can be
reached again. A reusable ADF Mobile feature is included in the sample code that you can use to show
the pending data synch actions to your mobile app end user.
2. Tutorial Setup
This section outlines the steps you'll need to follow to get your machine ready to go through this tutorial.
2.1. Prerequisites
This tutorial uses the sample HR schema that comes with the recent versions of the Oracle database. For
security reasons this schema is usually locked. We'll therefore unlock the user in the next steps. From a
command line invoke sqlplus and login using the system user; provide the password for the account. Type
the following command in the SQL> prompt

This tutorial requires Oracle JDeveloper 11g Studio Edition, release 11.1.2.4 Production. If you have a
version of Oracle JDeveloper installed, you can verify what version it is by selecting the Help | About
option from the main menu.

You can download the latest production release from OTN at
http://www.oracle.com/technology/software/products/jdev/index.html


You also need to install the ADF Mobile extension through the JDeveloper Help -> Check for Updates
menu. This tutorial requires at least ADF Mobile 11.1.2.4.1 extension (build 11.1.2.4.39.64.51) to be
installed.
2.2. Define a JDeveloper Connection for the HR Schema
Select View | Resouce Palette to show the Application Resources palet and follow these steps:

Create a New Database Connection.

Click on the Database folder, and select New Connection -> Database ... from the right-mouse menu.




Enter Connection Details.

Provide connection details as shown below.


2.3. Install Mobile Sample Accelerator Code Using "Check for
Updates"
The accelerator code is packaged an Oracle JDeveloper extension (or "plug-in") that you install using
JDeveloper's "Check for Updates" functionality.
To install the extension into your JDeveloper 11g 11.1.2.4 environment, perform the steps below.

Download the file to install the sample as JDeveloper extension

Download the install file from
http://www.ateam-oracle.com/?p=20078
. Go to the bottom of the blog article
for the download install link.

Run the "Check for Updates" wizard

With JDeveloper 11.1.2.4 running, choose Help | Check for Updates... from the main menu. Click
(Next>) on the Welcome page of the Check for Updates dialog.

Select the Local File

Click the Install from Local File button, and select the fiel you just downloaded using the Browse button.



Click Next.

Exit and Restart JDeveloper

On the Summary page of the wizard, click (Finish). The Confirm Exit alert appears because you need to
exit and restart JDeveloper to install the service update. Click (Yes) to exit. On Windows, JDeveloper will
exit and automatically restart. On Mac, Linux, or other platforms, JDeveloper will exit and you will need to
launch it again.

Acknowledge the Installation Alerts

When JDeveloper restarts, you may see the Confirm Overwrite alert, making you aware that the
automatic installer will be replacing a file in your JDeveloper installation. This is expected, so check the
Skip this Message Next Time checkbox, and click (Yes) to continue. When the Migrate User Settings
alert appears, click (No) to continue.

3. Creating a Mobile CRUD Application
3.1. Create and Configure a New Application
In JDeveloper, click ‘File’, ‘New’ and select ‘General > Applications’ in the category tree on the left. Next,
select Mobile Application (ADF). Click OK.

Give your Application an appropriate name and select a directory for usage. You can also specify a default
Java package where newly created classes will be stored.

You do not have to click Next, instead, click Finish to accept all defaults on the other pages of the wizard.
JDeveloper will now create a new application for you, with two projects: ApplicationController and
ViewController.
3.2. Add ADF Mobile Persistence Sample Libraries
Right-mouse-click on ApplicationController project, and choose Project Properties9 click on Libraries
and ClassPath, click the Add button and add the following two libraries to the project:
ADF Mobile Persistence Sample Designtime
ADF Mobile Persistence Sample Runtime



Repeat these steps for the ViewController project.
3.3. Create Java Objects and TopLink Mapping
In the ViewController project, go to New gallery, select all features, click on TopLink/JPA under business
tier and select “Java Objects from Tables”.



Run the Java Objects from Tables Wizard

Step 1: create a default TopLinkMap named tlMap, create a default offline database named DATABASE1
and select online HR db connection you created earlier.



Step 2: click next
Step 3: select DEPARTMENTS and EMPLOYEES tables
Step 4: enter appropriate package name, e.g oracle.mobile.hrcrud.model
Step 5: make the class names singular “Employee” and “Department”



Step 6:Only select the one-to-many relation between department and employee as shown below. By using
one-to-one relations, the mapping between the RESTful service payload and the domain object attributes
becomes more complex. While these more complex mappings are supported by the accelerator, it is just
easier to not create those mappings if not needed.



Click Next
Step 7: click Finish

NOTE: When you run this wizard for your own tables, you need to check the type of numeric attributes.
The wizard creates Integer attributes for numeric values with a precision (like CommissionPct in Employee
table), which causes a runtime conversion error when you run the mobile app later on. Change the type in
the generated Java class to BigDecimal if needed.

Create TopLink Mapping Deployment XML File

Rebuild the ViewController project. This will add a file named tlMap.xml to the META-INF directory of your
project. Now move this file to the META-INF directory of your ApplicationController project. In needs to be
in ApplicationController project so it is accessible during application startup.




Remove TopLink References in Generated Java Objects

Right-mouse-click on the Department.java class and run the utility Enable Class for ADF Mobile
Persistence.



The following changes are made by this utility.
The import org.eclipse.persistence.indirection has been replaced with
oracle.ateam.sample.mobile.persistence.indirection
The class extends the Entity class included in the accelerator runtime library
The field manager has been renamed to managerHolder.
A new field manager: private transient Employee manager has been added


Run this utility for the Employee.java class as well.

Remove Remaining TopLink Artefacts

Go to project properties of the ViewController project and remove the libraries TopLink and Oracle XML
Parser V2. Remove the same libraries from the ApplicationController project.
Also remove the sessions.xml file, located in the META-INF directory of your ViewController project.

Rebuild the project

As all TopLink references have been removed, you should be able to rebuild the project without errors.

3.4. Create CRUD Service Bean Class and Expose as Data Control

Create DepartmentService Class

Create a new Java class named DepartmentService and let it extend the sample code class
EntityCRUDService.






Remove the constructors, except for the no-arguments constructor.

Add code to implement abstracted methods as shown below.



Question: Can you figure out where these methods are used for by the accelerator runtime? Tip: run the
app in debug mode later on and set a breakpoint in these methods.

Also add the following method to provide a type-safe getter method for the array list of departments:



And finally , to autoquery the departments at feature startup, add the findAll method to the constructor:



That’s all. You now have set up a department crud service set that will support query, insert, update and
delete against the SQLite database that will be automatically installed on your mobile device. The same
service can also be easily configured to perform the same operations against a remote datasource using
Rest services, as we will see later in this tutorial.

Create Data Control for DepartmentService

To easily create mobile pages using drag and drop, we need to create a bean data control for this
DepartmentService. Right-mouse-click on the DepartmentService class in the navigator and choose
Create Data Control.
If you now go to the Data Controls palette, the DepartmentService should show up.

Set UI Hints for Department

Right-mouse-click on the departments node in the Data Controls palette and choose Edit Definition.



Click the UI Hints tab, and set the label of the various attributes.Set the label to “ID” for the departmentId
attribute.



This label will be used as the default label when creating mobile pages with the departmentId attribute.
Also set the label property for departmentName to “Name”.

Creating the SQLite Database at Application Startup If Needed

To initially create the SQLite database at application statup we will use the ability to configure a
LifecycleListener class.

We need to configure this listener in the adfm-application.xml file which can be found in the ADF META-
INF directory in the Resources palette.


Open this file, and use the search lamp at the right of the Lifecycle Event Listener field to select the
InitDBLifecycleListener class provided by the sample runtime library.



This listener class is a generic class that needs config information to know the SQLite database name,
table name to check whether the DB needs to be created, and the DDL script that must be executed when
the DB does not exist yet. The table name is found by looking up the TopLink mapping XML file that we
created earlier. The other information should be defined in a file named mobile-persistence-
config.properties. Copy the sample of this file and the ddl script that is supplied in the TutorialFiles.zip to
the META-INF directory of the ApplicationController project.

You also need to copy the tlMap.xml that is generated in the META-INF directory of the ViewController
project when you (re)build the project to the META-INF folder in the ApplicationController project.

Remove the sessions.xml file in the META-INF directory of your ViewController project. It is not needed
and will give an error when you are trying to deploy your mobile application.




Open the config properties file and check the property settings, if you followed the instructions of this
tutorial there should be no need to change them.


Testing DepartmentService in JDeveloper

Note the last three entries about a test database. This can be used to test your CRUD DepartmentService
class directly in JDeveloper. The accelerator runtime code will check whether you run on a mobile device
or emulator, and if not it will connect to the database that you specified through these properties.

If you want, you can add a main method to your DepartmentService class and test this feature. Note that
to be able to find the ADFmobile framework classes, you need to add all the jars located in
<jdev_home>\jdev\extensions\oracle.adf.mobile\lib to your project.

3.5. Creating the Department List Page
We are now ready to create our first page that will display a list of departments. We create the page inside
a task flow, so we will create an ADF Mobile feature that launches a task flow.

Creating the task flow feature

Go to the adfm-feature.xml and create a new feature named Departments.


Then click on the “Content” tab and then click on the green plus icon at the right of the File field, and
create a new ADF task flow named departments-task-flow.




Creating the Department List Page

Drag and drop a View activity on the task flow diagram and name it DepartmentList. Double-click on the
view activity to create the page. Uncheck the checkbox Primary Action.



Set the header text to “Departments” and drag and drop the departments data collection from the Data
Controls palette onto the page as ADF Mobile List View.



Accept the default list view settings and set the first text element to DepartmentName.




Add Search Functionality to the Department List Page

We will add a search field and button to restrict the list of departments based on the value of this search
field. The A-team sample code contains out-of-the-box functionality, where a searchValue is applied to all
underlying columns that are of the proper type. Columns of String type are searched using the LIKE
operator and the searchValue is suffixed with a wildcard. If the searchValue is a numeric value, then all
numeric columns are also included in the WHERE clause using the = operator.

To add this search functionality to the page, you drag and drop the find(String) method as ADF
Mobile Parameter Form at the top of the page, just above the listView element.



Click OK in the Edit Form Fields dialog that appears. Clean up the layout by changing the lines that
include the search field and button as follows:




Test the Department List Page

You are now ready to run your application on your mobile device or emulator. Create a new deployment
profile and deploy the application .
Test the case insensitive search functionality by entering the first character of a department name.

For a deeper understanding of the persistence functionality and features, you can enable debugging and
set a breakpoint in the DepartmentService constructor and debug step-by-step how all departments are
queried from the SQLite database.

3.6. Creating Department Edit Page

Add another view activity to the task flow, and name it EditDepartment.Check both the primary and
secondary facets.
Set the header to “Edit Department”, make the button in the primary facet to go back to previous page.

Drag and drop the departmenst from the Data Controls palette to the page as Form -> ADF Mobile
Form

In the Edit Form Fields dialog, remove all attributes except departmentId and departmentName.




Add Save Action

To save the changes, you drag and drop the mergeEntity method from the DataControls palette into
the secondary facet as ADF Mobile Button. This opens up the Edit Action Binding dialog. In this dialog,
you need to provide an EL expression for the “entity” parameter. You can use the “Show EL Expression
builder” dialog to help you constructing the following expression:

#{bindings.departmentsIterator.currentRow.dataProvider }




Set the text of the button to “Save”, the action property to “__back” and remove the existing button in the
secondary facet.

Add Employees List to Edit Department Page

We will now add a list of employees that work in the selected department to the Edit Department page.
First, add a getEmployees method to the Department class that returns an array of employees.



Now, drag and drop the employees collection under departments from the Data Controls palette as
List view to the Edit Department page.



Display the lastName in the list, and add a header text “Employees” in between the department fields
and the employee list.

Wire Department List Page to Edit Page

When tapping on a department in the list, we should navigate to the edit page.

First add a control flow case on the task flow diagram and name it “edit”.



Now, go back to the Department List page and set the action property of the <amx:listItem> element to
“edit”.

Set Current Department

The last step is to make sure the current department is set when navigating to the edit page. To set the
current row, we can use the following setPropertyListener inside the amx:listItem element.



However, while this sets the current row in the departmentsIterator of the DepartmentLits page definition,
this row currency is not preserved when navigating to the edit page. This functionality will be added in a
future release of ADF Mobile.
To minimize the steps you need to do to make this work in the current release, and to best prepare for this
future functionality, the A-team sample code provides a subclass of
oracle.adf.model.adapter.bean.BeanDCDefinition ,named
oracle.ateam.sample.mobile.model.bean.StatefulIteratorBeanDcDefinition that
ensures the row currency is preserved across pages that use the same iterator id and iterator binding
path.

So, all you need to do is specify this subclass as the value of the ImplDef property of the
AdapterDataControl element in DataControls.dcx file.



This file can be found in the default view package of your project.

Test the Application

Now deploy and run the application and check whether the navigation and update works correctly.

You can set a breakpoint in the Department.getEmployeeCollection method so you can check
line-by-line how the employee collection is lazily loaded when the method is called for the first time.

3.7. Add Create Department Functionality

Add Create Method Activity

Drag and drop the Create operation inside the secondary facet of the DepartmentList page.


Set the button text to “New”. Set the action property to “edit” to perform navigation to the edit page.



Add addDepartment method to DepartmentService

The Create operation will automatically create a new instance of a department, and add this instance to
the iterator. We also want to add this instance to the underlying department list maintained in the
department service. Add the following method to the DepartmentService.java class:



The ADF Mobile framework will recognize the name and signature of this method, and will automatically
cal this method when you click the New button.

Make title in edit department conditional based on new entity state

The title in the EditDepartment page is hardcoded to “Edit Department”. However, when we click the New
button the list page, we want to show “New Department as title. To achieve this, we need to add the
following value binding to the EditDepartmentPageDef.



With this binding in place, we can now use the following EL expression in the page header facet
outputText:


3.8. Adding Delete Function to Departments List Page
To finish the basic CRUD functionality, we will add delete functionality to the Departments list page. The
delete button should appear when the user swipes to the right on a department row. The button should be
right aligned. Pressing the button should subsequently delete the row from the database.

Add Delete button

Drag and drop the Delete operation as button inside the list item element.




Set current row when clicking the Delete Button

Use a setPropertyListener inside the delete button to set the current department.



Add removeDepartment method to DepartmentService

The Delete operation will automatically remove the current department from the iterator. We also want to
remove this instance from the underlying department list maintained in the department service and from
the local and/or remote persistence store (if configured). Add the following method to the
DepartmentService.java class to accomplish this:



The ADF Mobile framework will recognize the name and signature of this method, and will automatically
cal this method when you click the Delete button. The removeEntity method is provided by the A-team
sample code and will take care of removing the department from the list.

Show/hide the delete button with swipe right/left actions

Use a setPropertyListener with type “swipeRight” on the list item to set the departmentId a viewScope
variable “showDeleteButtonKey”. Add another setPropertyListener with type “swipeLeft” that will clear the
viewScope variable again.



Add a rendered expression to the delete button that only makes the button visible when the
showDeleteButtonKey variable contains the department is of the current row in the list.

rendered="#{row.departmentId==viewScope.showDeleteButtonKey}"

RightGalign the delete button

When the delete button becomes visible after a swipe action, it should be left aligned. You can use nested
panelGroupLayout elements to achieve this layout:



4. Adding Remote Persistence Using ADF BC Rest Service
So far, we have implemented the CRUD functionality using a local SQLite database. In most cases, you
will initially retrieve the data from a remote server, and also send data changes to this remote server. We
will now add this functionality.
4.1. Set up the ADF BC Rest Service
Unzip the HRDemoRest zip file. Open the HRDemoRest.jws in JDeveloper and modify the connection
details as needed to connect to your local HR schema.
Now run HRDemorest web application, by clicking Run while selecting the ViewController project
node.This will start the ADF Faces web application.

Test the Rest Services

In the Readme.txt file in the root directory of the REST application, you can find the URL’s and payload
you can use to test the two REST services.

The host name in the URL of the web application and REST services depends on how you have set up
the embedded weblogic server. To call the REST services from your mobile device, you cannot use
localhost or 127.0.0.1, you need to use the actual IP address of yout PC/laptop. So use ipconfig and use
the IP address to test the REST services again. If that doesn’t work, make sure that your embedded
weblogic will allow access using the IP address. This can be done by checking the config.xml which can
typically be found using a path like this:

C:\Users\sdavelaa\AppData\Roaming\JDeveloper\system11.1.2.3.39.62.76.1\DefaultDomain\config

In the config.xml file, there is an element listen-address that should be empty:

<listen-address></listen-address>

If it is not empty, then make it empty and restart WLS.

Only continue with the exercise if your REST services can be accessed using the IP address.

4.2. Create a URL Connection in the Mobile Application
To call the REST services you need to create a URL connection that connects to your machine using your
IP address.

Go to the New Gallery and choose URL Connection.




Give the connection a logical name, enter your IP address and port 7101 and test the connection.



Now go into the mobile-persistence-config.properties file and make sure that rest.connection property
has the same name as the connection you just created.



4.3. Add Remote Persistence Manager to DepartmentService

To invoke the remote REST services to query, insert, update and delete departments, we only need to
plug in an additional remote persistence manager, in addition to the local persistence manager that
persists to the SQLite database. The HRDemoRest application supplied, supports both a REST-XML API,
as well as a REST-JSON API.

Depending on which RESTful service protocol you want to use, you can either use one of the following
persistence manager that come with the A-team sample code:
 A RestADFBCXMLPersistenceManager
 A RestJSONPersistenceManager

To plug in the RestADFBCXMLPersistenceManager, add the following code to the DepartmentService
class:

private static final String WRITE_REQUEST_URI = "/hrdemorest/rest/xml/WriteDeps";
private static final String WRITE_PARAM_NAME = "xml";
private static final String READ_REQUEST_URI = "/hrdemorest/rest/xml/ReadDeps";
private static final String ROW_ELEMENT = "DepartmentsViewRow";
private static final String ROOT_ELEMENT = "DepartmentsView";

public DepartmentService() {
RestADFBCXMLPersistenceManager remotePersistenceManager =
new RestADFBCXMLPersistenceManager(READ_REQUEST_URI,WRITE_REQUEST_URI,WRITE_PARAM_NAME
,ROOT_ELEMENT, ROW_ELEMENT);
setRemotePersistenceManager(remotePersistenceManager);
setDoRemoteReadInBackground(true);
setDoRemoteWriteInBackground(true);
super.findAll();
}

To plug in the RestJSONPersistenceManager, add the following code to the DepartmentService class:

private static final String WRITE_REQUEST_URI = "/hrdemorest/rest/json/WriteDeps";
private static final String WRITE_PARAM_NAME = "json";
private static final String READ_REQUEST_URI = "/hrdemorest/rest/json/ReadDeps";
private static final String REMOVE_REQUEST_URI = "/hrdemorest/rest/json/RemoveDeps";
private static final String ROOT_ELEMENT = "DepartmentsView";

public DepartmentService() {
RestJSONPersistenceManager remotePersistenceManager =
new RestJSONPersistenceManager(READ_REQUEST_URI,WRITE_REQUEST_URI,WRITE_PARAM_NAME
,REMOVE_REQUEST_URI ,ROOT_ELEMENT);
remotePersistenceManager.setInitCapPayloadAttrs(true);
setRemotePersistenceManager(remotePersistenceManager);
setDoRemoteReadInBackground(true);
setDoRemoteWriteInBackground(true);
super.findAll();
}


That’s all. The A-team sample code will take care of invoking the REST services. When you now launch
your mobile app again, the local database will be updated with all departments that are returned through
the remote Rest service call. When you insert, update or delete a department, the action will be performed
both on the local SQLite database as well as the remote HR database through the REST service calls.

By default the remote read and write actions will be performed in the background, so when you start the
mobile app you will first see the list of departmenst stored in the local DB, and after a few seconds the
screen will refresh and should show the list of departments as stored in the remote database.

4.4. Mapping Payload Attributes to Entity Attributes

In this tutorial, the RESTful services provided, use the same attribute names as the attributes in the
generated Department and Employee entity objects.The only difference is the first letter of the
attribute,which starts with an uppercase in the payload. Method setInitCapPayloadAttrs(Boolean)
can be used to configure this difference, as you might have seen above when using the
RestJSONPersistenceManager class. The RestADFBCXMLPersistenceManager already calls this
method with value true in its constructor because in ADF BC all attributes always start with an uppercase.
Now, if you have a situation where the payload attribute names are really different, you can add an
additional entry in the toplink mapping xml file.

For example, if the payload contains the attribute “Id” rather than “DepartmentId” you can modify the
toplink mapping xml file and add a payload-attribute-name tag as follows:



Note that you need to make this change outside JDeveloper because the file is read-only inside
JDeveloper.

Date Format in Payload Attributes
The date and datetime format used in the payload attributes can be configured in mobile-
persistence-config.properties:



When converting the Rest payload to entity objects, the accelerator runtime first tries to use the datetime
pattern for conversion, if that fails, the date pattern is used.

When converting an entity attribute to JSON/XML string value, a configurable boolean property
useDateTimeFormat (default=true) in the persistence manager is used to decide whether the datetime
or date pattern is used for the conversion.

4.5. Delayed Data Synchronization
When the mobile device is online and the remote REST server is up and running, any change you make to
the data, will be sent directly to the remote server if you configured a remote persistence provider.
If you are making data changes while the device is offline, or the remote server is unavailable for some
other reason, the accelerator runtime code will automatically save these pending data synchronization
actions. When the remote server is available again, the data synchronization will take place automatically
when you start using the application again.
The accelerator ships with a reusable mobile feature that you can plug into your own application to allow
the user to view his pending data synchronization actions, remove them if desired, or start a
synchronization session manually.
Follow the steps below to add this feature to your tutorial application.

Add the reusable DataSync feature to your application

Go to Application -> Properties in the JDeveloper menu, and click the Add JAR/Directory9 button.
Select the jar file DataSynchFeature.jar that is located in
<jdev_home>\jdev\extensions\oracle.ateam.sample.mobile.persistence.



Now, open the adfmf-application.xml file, which can be found in the Application Resources
palette in the ADF METAGINF directory. Click the green plus icon to insert a feature reference and select
the oracle.ateam.sample.mobile.datasynch feature.




Click OK, and set the Show on Navigation Bar and Show on Springboard properties to false.

Add button to navigate to DataSync feature

We need a managed bean to navigate to the DataSynch feature. For this managed bean we can use a
bean class that is included in the accelerator runtime.
Go to the Overview tab of the adfc-config-mobile.xml file, and add a managed bean with the
following properties:
 Name: GoToFeature
 Class: oracle.ateam.sample.mobile.controller.bean.GoToFeatureBean
 Scope: application





It is important that you use exactly the name “GoToFeature”, otherwise, the back button will not work in
the DataSynch feature page.

With this managed bean in place, we can now add a button in the primary facet of the DepartmentList
page as shown below:

<amx:facet name="primary">
<amx:commandButton text="Sync" id="cb1"
actionListener="#{GoToFeature.goToDataSynchFeature}">
<amx:setPropertyListener id="spl3" from="oracle.demo.hrcrud.mobile.model.Department"
to="#{applicationScope.dataSynchEntity}"/>
</amx:commandButton>
</amx:facet>

Make sure you change the value of the from property in the setPropertyListener to match the
package name you have used for your entity objects.

If you only want to show the Sync button when there are pending synch actions , you need to add the
following rendered expression to the button:

rendered="#{bindings.hasDataSynchActions.inputValue}"

This expression needs a value binding hasDataSynchActions, the fastest way to add that binding to
the page definition is to drag and drop the hasDataSynchActions attribute from the Data Controls
palette as an outputText and then remove the outputText again.



Viewing pending data sync actions

If you created, updated or removed a department, and the remote data synch action failed for some
reason, they will be stored as pending data sunch actions. You can view these pending actions by clicking
the Sync button we added in the previous step. Note that it might take a while before the actions are there
because they are executed in the background and the server timeout period might impact how long you
have to wait.

If you click the button, you will get a list of the pending sync actions, and when you tap on one the list
items, you will get a popup with the details of the synch action, as shown below.



There is also a Synchronize button (hidden behind the popup on this screenshot) to manually start
another sync process. In situations where the sync action keeps failing, for example because the data is
invalid, or stale, the user can manually remove the data synch action using the Remove button in the
popup.

Note that the accelerator runtime code assumes that the remote server is responsible for preventing late
updates on data that has been changed in the meantime by other users. If you need this kind of stale data
detection, your data model should contain a version number, or date last modified attribute that is included
in the payload and also stored on the mobile device. Then, the server can send an error message that will
be shown in this screen as Last Synch Error.