Any discussion around user interface capability inherently entails a discussion around mobile enablement. Organizations are making concerted efforts to understand how to develop and extend user experiences to a wide range of mobile devices.
Oracle’s ADF Mobile allows companies to develop leverage the power of declarative development and data binding to enable mobile experiences for new and existing systems.
In this episode of the Enterprise 2.0 Workbench we take a look if using ADF Mobile to create an interface on top of WebCenter Content. We do this using a web service data control that is being generated on top of a Java Bean connecting to Content Server. Our Java Bean uses RIDC to connect to content server and although it is not necessarily best practice to layer a web service on top of a bean using RIDC (RIDC uses services to call into Content Server – creating additional service traffic), it gives us a sense of how we can use existing services or services that are quickly enabled through a plain old job object to create our mobile interfaces.
Simple Example Scenario
In our example to create a mobile interface on top of the sales library to enable our sales people in the field to get the most recent, approved content items to help them do their job.
For organizations looking for true production mobile capabilities for WebCenter Content should review
Let’s dive in and review the various components within our simple example solution.
WebCenter Content
The basic sales library that we will expose via our mobile interface is supplied using WebCenter Content to secure and categorize the sales assets.

AMX Mobile Pages
Our solution only consists of two pages. These pages are created using ADF Mobile’s AMX tags. The DocView.amx will recursively call itself if a user chooses to drill into a folder within the interface. If a user selects a document the view will be routed to DocView.amx.

Document List Views – amx:setPropertyListener and amx:listView
For each selection we will store the relevant ID code in a managed bean associated with our application. This is done by including an amx:setPropertyListener within each list item to set the selected node. Once the row is selected, the managed bean’s GetCollection method will be called to refresh the data bound to 2 amx:listView components.
DocView.amx
<?xml version="1.0" encoding="UTF-8" ?>
<amx:view xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:amx="http://xmlns.oracle.com/adf/mf/amx"
xmlns:dvtm="http://xmlns.oracle.com/adf/mf/amx/dvt">
<amx:panelPage id="pp1">
<amx:listView var="row" value="#{bindings.viewFolders.collectionModel}"
fetchSize="#{bindings.viewFolders.rangeSize}" id="lv1">
<amx:listItem id="li1" actionListener="#{pageFlowScope.DemoBean.GetCollection}" action="showDocs">
<amx:setPropertyListener from="#{row.collectionID}" to="#{pageFlowScope.DemoBean.selectedNode}" type="action"/>
<amx:tableLayout id="tl2">
<amx:rowLayout id="rl3">
<amx:cellFormat id="cf4" width="40px">
<amx:image id="i1" source="/Images/folder_32.png"/>
</amx:cellFormat>
<amx:cellFormat id="cf5">
<amx:outputText value="#{row.collectionName}" id="ot4"/>
</amx:cellFormat>
</amx:rowLayout>
</amx:tableLayout>
</amx:listItem>
</amx:listView>
<amx:listView var="row" value="#{bindings.viewItems.collectionModel}" fetchSize="#{bindings.viewItems.rangeSize}"
id="lv2">
<amx:listItem id="li2" action="showDetail">
<amx:setPropertyListener from="#{row.URL}" to="#{pageFlowScope.DemoBean.docURL}" type="action"/>
<amx:setPropertyListener from="#{row.title}" to="#{pageFlowScope.DemoBean.docName}"/>
<amx:tableLayout width="100%" id="tl1">
<amx:rowLayout id="rl1">
<amx:cellFormat width="40px" rowSpan="2" id="cf2">
<amx:image id="i2" source="/Images/page_32.png"/>
</amx:cellFormat>
<amx:cellFormat width="100%" height="28px" id="cf1">
<amx:outputText value="#{row.title}" id="ot5"/>
</amx:cellFormat>
</amx:rowLayout>
<amx:rowLayout id="rl2">
<amx:cellFormat width="100%" height="12px" id="cf3">
<amx:outputText value="#{row.author}" styleClass="adfmf-listItem-captionText" id="ot6"/>
</amx:cellFormat>
</amx:rowLayout>
</amx:tableLayout>
</amx:listItem>
</amx:listView>
<amx:facet name="header">
<amx:outputText value="Browse" id="ot1"/>
</amx:facet>
<amx:facet name="primary">
<amx:commandButton text="Home" id="cb3" actionListener="#{pageFlowScope.DemoBean.GoHome}" action="showDocs"/>
</amx:facet>
<amx:facet name="secondary">
</amx:facet>
</amx:panelPage>
</amx:view>
DetailView.amx
<?xml version="1.0" encoding="UTF-8" ?>
<amx:view xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:amx="http://xmlns.oracle.com/adf/mf/amx"
xmlns:dvtm="http://xmlns.oracle.com/adf/mf/amx/dvt">
<amx:panelPage id="pp1" inlineStyle="background-color:White;">
<amx:facet name="header">
<amx:outputText value="#{pageFlowScope.DemoBean.docName}" id="ot1"/>
</amx:facet>
<amx:facet name="primary">
<amx:commandButton id="cb1" text="Back" action="__back"/>
</amx:facet>
<amx:facet name="secondary">
</amx:facet>
<amx:commandButton text="View Content" id="cb2"
actionListener="#{pageFlowScope.DemoBean.callFramedDocumentJS}"/>
<amx:verbatim id="vb1"/>
</amx:panelPage>
</amx:view>
Data Controls used to Create amx:listView
The 2 amx:listView components in the DocView.amx were declaratively based on the following controls that were dragged and dropped into the AMX page. The data controls were created by creating a new “Web Service Data Control” in our project based on a WSDL from our service layer on top of Content Server.

Managed Bean in ADF Mobile
Our managed bean does the heavy lifting in our example. It contains a series of methods that are called from our AMX page using actionListener attributes of our components.
Managed Bean DocBean.java
package mobile;
import java.util.ArrayList;
import java.util.List;
import javax.el.ValueExpression;
import oracle.adfmf.amx.event.ActionEvent;
import oracle.adfmf.framework.api.AdfmfContainerUtilities;
import oracle.adfmf.framework.api.AdfmfJavaUtilities;
import oracle.adfmf.framework.exception.AdfInvocationException;
import oracle.adfmf.java.beans.PropertyChangeListener;
import oracle.adfmf.java.beans.PropertyChangeSupport;
public class DocBean {
// Start node for the document viewer (dCollectionID)
private String rootCollectionNode = "727456639941000002";
// Track the currently selected node
private String selectedNode = rootCollectionNode;
// Link to converted content
private String docURL = "";
// Name of content item that has been selected
private String docName = "";
private transient PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
public DocBean() {
super();
}
// Store the seclected node for a given folder in the UI
public void setSelectedNode(String selectedNode) {
String oldSelectedNode = this.selectedNode;
this.selectedNode = selectedNode;
propertyChangeSupport.firePropertyChange("selectedNode", oldSelectedNode, selectedNode);
}
public void addPropertyChangeListener(PropertyChangeListener l) {
propertyChangeSupport.addPropertyChangeListener(l);
}
public void removePropertyChangeListener(PropertyChangeListener l) {
propertyChangeSupport.removePropertyChangeListener(l);
}
public String getSelectedNode() {
return selectedNode;
}
// Set selected node to the root of the content systems as set above
public void GoHome(ActionEvent actionEvent) {
// Change the bean attribute of selectedNode to the root
ValueExpression ve =
AdfmfJavaUtilities.getValueExpression("#{pageFlowScope.DemoBean.selectedNode}", String.class);
String selectedNode =
String.valueOf(rootCollectionNode);
ve.setValue(AdfmfJavaUtilities.getAdfELContext(), selectedNode);
}
// Set the current folder that we will query
public void GetCollection(ActionEvent actionEvent) {
ValueExpression ve =
AdfmfJavaUtilities.getValueExpression("#{pageFlowScope.DemoBean.selectedNode}", String.class);
String selectedNode = (String)ve.getValue(AdfmfJavaUtilities.getAdfELContext());
ve.setValue(AdfmfJavaUtilities.getAdfELContext(), selectedNode);
}
// Call custom Javascript to inject an iFrame
public void callFramedDocumentJS(ActionEvent actionEvent) {
AdfmfContainerUtilities.invokeContainerJavaScriptFunction("DocB", "showFramedDocument",
new Object[] { "" + docURL + "" });
}
// Set the URL for the web viewable version of a document / content item
public void setDocURL(String docURL) {
String oldDocURL = this.docURL;
this.docURL = docURL;
propertyChangeSupport.firePropertyChange("docURL", oldDocURL, docURL);
}
public String getDocURL() {
return docURL;
}
public void setDocName(String docName) {
this.docName = docName;
}
public String getDocName() {
return docName;
}
}
Custom Javascript to Open Iframe
For complete details of our custom Javascript that opens the iframe to our content check out our prior post ADF Mobile Custom Javascript – iFrame Injection.
Sample Application Download
ADF Mobile Development Resources
During this exercise the following resources proved extremely helpful.
- Oracle® Fusion Middleware Mobile Developer’s Guide for Oracle Application Development Framework 11g Release 2 (11.1.2.3.0)
- Oracle Fusion Middleware Java API Reference for Oracle ADF Mobile
- Class AdfmfJavaUtilities – very helpful in understanding what objects are available to leverage within ADFMF in your managed beans
- ADF Mobile Component Demos