create mobile (Android) clients [since
4.1]
The version 4.0 of OBEROn platform introduced the Androd Extension Library (AEL): it is a single java package (jar) that you can include inside the Android applications you are developing. It allows to connect your mobile device to the company server and provides all java SDK classes to retrieve, manage and save business object instances without caring about the connection protocols or the security issues. In this way, you can reuse all the business logic at the server side and limit the development only to the high level user interfaces (note that also the user interface logic, like user input data checks, selection values and the input masks are also computed inside the OBEROn http server).
Like for desktop clients, there are two main classes that allows you
to develop a desktop client:
- Application: is the basic class for mobile apps. It is included inside the Android Extension Library; it extends the Android Activity class and provides connection methods and other utility functions.
- OberonClient:
is a primal Android mobile client; custom Android apps should extend this Activity class or they should have a similar logic.
Mobile clients require an HTTP server for connecting to the OBEROn database and performing actions on object instances. You can setup a light OBEROn HTTP server with a minimal configuration, just download it from the "Downloads" page and edit the oberon.properties file (case D) like we have seen for web-applications.
A simple example of the usage of Android Extension Library is the OOQL console for Android. You can dowload the OOQL Client - Eclipse Project , compile it with Eclipse and upload the apk file to the mobile device or you may download the already compiled version from the Google Play app-store. This app allows to execute OOQL commands and queries on the OBEROn server through Android mobile devices.
The OberonClient class is a part of Android Client - Eclipse Project and contains basic functionalities
for developing a standard Android application based on the AEL; you can compile it with Eclipse and upload the apk file to the mobile device or you may also download a compiled version from the Google Play app - store.
The configuration
parameters for Android can be store into the activity Shared Preferences; in particular you have to define the server URL and the application parameter. The first is absolutely required for contacting the server and exchanging data; the second is also required for creating the application menu and accessing the user interface functionalities. The application value may also be hard coded into the java source when the client is specialized for a single application (or portfolio).
To define the possible actions that each user can execute
inside the application you must create a set of commands organized
into menus and submenus. Menus created for a web/desktop applications can
be used also in mobile clients. The first "page" the client shows after the login is the
welcome page.
The mechanism that is used inside the mobile app to pass from a page to another is the same of that described for the desktop clients. The classes
"ApplicationRequest"
and "ApplicationSession" represent the page request and the current session respectively.
The most important method of in the OberonClient is:
handleRequest(ApplicationRequest
request)
This method redirects the input request to another specific
method according to the requested page (or URL) declared inside
the ApplicationRequest itself. It means that for each web URL associated
with menu commands there should be a method that represents the
equivalent web-page in Android format, like in the following example:
The "TAGS.PAGE_<PageName>" constant values correspond to the web page names (for example "edit.jsp" / "files.jsp" / "lifecycle.jsp" ..... )
Note: page URLs inside the command Href parameter may start with
the webapp relative path; for this reason you should use the "endsWith"
or "indexOf" comparison operators instead of "equals".
The window manager in a desktop client is implemented by two methods:
createPagePanel : prepares the page layout adding the title bar with title / subtitle, object contextual menu (when required) and manages error messages.
addPageToContainer: add the page panel to the proper page container accordind to the ApplicationRequest target; if target is:
-
"" (empty) uses the same container of input request referer
- "_blank"
opens a new tab folder
- "<Window Name>"
replace the content of popup dialog with corresponding name
The first page opened after the login is the TAGS.PAGE_Home (equals to "home.jsp")
renderized by the doHome method.
The following examples show how basic functionalities are implemented with Android controls.
TAGS.PAGE_Edit = edit.jsp -> doEdit
The following method can perform both the object
creation and the object data update (if the input ID is passed as
input parameter). It also manages both the user interface for data
input (createForm) and the database update process (saveFormData).
These two methods are defined into the Forms
class. The Forms class represents the Android implementation for
the form administrative objects: in other words it generates the
java code based on the form parameters and on the form-item parameters,
included all the code needed to load/refresh the field ranges and
to validate the field-item values.
public void doEdit(ApplicationRequest request) {
try { |
|
ApplicationSession session = (ApplicationSession) request.getSession();
// Get the object
id as input parameter
String sID = request.getParameter(TAGS.id);
ObjectObj object;
boolean bCreateNew;
boolean bClone = false;
if ( sID==null || sID.length()==0 |
|
|
|| HTMLUtil.getInputParameter(TAGS.create,request).equals("true")
) {
// Create a new
object
bCreateNew=true;
object = new ObjectObj(); |
|
} else { |
|
|
// Open the object
and read its properties
sID=sID.trim();
bCreateNew=false;
if (HTMLUtil.getInputParameter(TAGS.clone,request).equals("true")
) {
bClone = true;
}
object = ObjectObj.open(sID,true,framework); |
|
}
// Get the create/edit Form name
as input parameter
String sFormName = HTMLUtil.getInputParameter(TAGS.form , framework);
if ( sFormName.length()==0)
{ |
|
|
// When the form
is not passed as input parameter try to get it from the
object class
sFormName = object.getClass(framework).getDefaultForm(true); |
|
}
Form form = Form.open(sFormName , framework , null );
// Save the object data or create
it
String sForwardPage=Forms.saveFormData(bCreateNew?TAGS.PAGE_Edit:"",object,form,request);
if ( sForwardPage.length()>0 ) { |
|
|
//
A new object is succesfully created - go forward to the
object detail page
ApplicationRequest fwrequest = new ApplicationRequest
(sForwardPage,request.getForwardTarget(),session);
fwrequest.setLocale(request.getLocale());
fwrequest.setReferer(request.getReferer());
handleRequest(fwrequest);
return; |
|
}
// Define
title and subtitle for the menu bar
String sTitle = Dictionary.getKey(dictionary_Section,sFormName,framework);
String sSubTitle = "";
if ( sID!=null && sID.length()>0 ) { |
|
|
if (bCreateNew) {
//
Clone an existing object
object
= ObjectObj.open(sID,true,framework);
object.resetID();
}
sSubTitle=sTitle;
sTitle= getClassNameRevision(object,session); |
|
}
// Creates
the page container (includes the menu bar with title and
subtitle)
LinearLayout globalpanel = createPagePanel(this, sTitle,
sSubTitle, !bCreateNew, request);
if (globalpanel!=null)
{ |
|
|
// Generate the
Android form compiled with object field values
ScrollView panel=Forms.createForm(globalpanel,TAGS.PAGE_Edit,object,form,request);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout .LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
globalpanel.addView(panel,params);
// Add the page container to
the application window (tab widget or alert dialog)
String sPrefix = sSubTitle.length()>0?"("+sSubTitle.substring(0,1)+")
":"";
addPageToContainer(globalpanel,sPrefix+sTitle,request); |
|
} |
} catch (Exception ex) { log(ex.getMessage()); }
} |
|
TAGS.PAGE_Search = search.jsp
-> doSearch
The doSearch method is similar to the doEdit: it
manages the user interface for the query input filters (createSearchForm);
this method is also defined into the Forms class. It requires
the search form name as input value and generates the Android code based
on this form parameters and on its item parameters.
public
void doSearch(ApplicationRequest request)
{
try
{ |
|
ApplicationSession session = (ApplicationSession) request.getSession();
// Get the search Form name as
input parameter
String sFormName = HTMLUtil.getInputParameter(TAGS.form , request);
if ( sFormName.length()==0)
{ |
|
|
log("NO
INPUT FORM");
return; |
|
}
Form form = Form.open(sFormName , framework , null );
String sTitle = Dictionary.getKey(dictionary_Section,sFormName,framework);
|
|
// Creates
the page container (includes the menu bar with title and
subtitle)
LinearLayout globalpanel = createPagePanel(this, sTitle, "",false,
request);
if (globalpanel!=null)
{ |
|
|
//
Generate the SWT form compiled with object field values
ScrollView panel = Forms.createSearchForm(globalpanel,TAGS.PAGE_SearchResults,form,request);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout .LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
globalpanel.addView(panel,params);
// Add the page container to
the application window (tab widget or alert dialog)
addPageToContainer(globalpanel,sTitle,request); |
|
} |
}
catch (Exception
ex) { log(ex.getMessage()); }
} |
|
TAGS.PAGE_SearchResults = search_results.jsp
-> doSearchResult
This method executes the search query based on the
filters defined into the doSearch. It employs the searchObjects method
included into the Forms class. In addition, you can apply a
view to the query results to extract and show several object properties.
public
void doSearchResult(ApplicationRequest request)
{
try
{ |
|
ApplicationSession session = (ApplicationSession) request.getSession();
// Get the search Form name as
input parameter
String sFormName = HTMLUtil.getInputParameter(TAGS.form , request);
if ( sFormName.length()==0)
{ |
|
|
log("NO INPUT
FORM");
return; |
|
}
Form form = Form.open(sFormName , framework , null );
String formHTMLName=Forms.getFormHTMLName(form);
// Execute the search query
try { |
|
|
String sMessage = Forms.searchObjects(
form , request );
if (sMessage.length()>0)
{
if
(sMessage.startsWith(TAGS.FORM_ActionAlert+"("
)) {
sMessage=
StringUtils.getStringPart( sMessage,TAGS.FORM_ActionAlert+"(\"", "\");"
);
}
showMessage(app,sMessage,"",null);
} |
|
} catch
(Exception e) { |
|
|
log(e.getMessage()); |
|
}
// Get user views
Vector vViews = com.oberon.ooql.sdk.View.getUserViews(framework);
// Prepare the view list
String sViews = HTMLUtil.getInputParameter(TAGS.views ,request);
Vector vFormViews = StringUtils.StringTokensToVector(sViews,"|");
for (int i=vViews.size()-1;i>=0;i--)
{ |
|
|
if
(vFormViews.indexOf(((String)vViews.elementAt(i)))<0)
{ vViews.removeElementAt(i);}
|
|
}
String sView = HTMLUtil.getInputParameter(TAGS.view,request); |
|
// Creates
the page container (includes the menu bar with title and
subtitle)
LinearLayout globalpanel = createPagePanel(this, sTitle, "",false,
request);
if (globalpanel!=null)
{ |
|
|
//
Generate the Android table for search result
ResultSetPanel rst = new ResultSetPanel(globalpanel,request);
//
Set the listener for showing the object contextual menu when the user click on a table row
rst.getTable().setOnRowLongClickListener( new OnLongClickListener() {
public boolean onLongClick(View view) {
try {
String sID = (String) getData(view,TAGS.ID);
Forms.fillObjectPopUpMenu(view,sID,null,(ApplicationSession)request.getSession());
} catch (Exception exx) {
}
return true;
}
}
);
// Load the view list in the
result set panel rst.resetViews(sView,vViews);
// Process the search result
Vector
rst.process( Forms.getSearchResults( formHTMLName
, session ) );
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout .LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT);
globalpanel.addView(rst.panel,params);
// Add the page container to
the application window (tab widget or alert dialog)
addPageToContainer(globalpanel,sTitle,request); |
|
} |
}
catch (Exception
ex) { log(ex.getMessage()); }
} |
|
TAGS.PAGE_Files = files.jsp - doFiles
This method shows the object's attached files and
enables the user to perform operations on them (open, extract into
a local folder, attach more , remove )
TAGS.PAGE_Lifecycle = lifecycle.jsp -> doLifecycle
This method loads the object's lifecycle and
generates its graphical representation. The user will be able to
progress or regress the status and to validate/refuse the path validations.
TAGS.PAGE_Navigate = navigate.jsp -> doNavigate
Shows the object's navigation tree: links can
be filtered selecting the linktype and the direction.
TAGS.PAGE_Activity = activity.jsp -> doActivityList
TAGS.PAGE_ActivityCompletion=default_step_completion.jsp ->doActivityCompletion
Visualizes the user activity dashboard and opens
the default completion popups when Href is not specified in workflow
steps.
|