Oracle® Fusion Middleware Mobile Client Developer's Guide for Oracle Application Development Framework 11g Release 1 (11.1.1.5.0) Part Number E14826-02 |
|
|
View PDF |
This chapter includes the following sections:
Section 7.1, "About Invoking Custom Methods Through EL Expressions"
Section 7.3, "Using a Managed Bean in an ADF Mobile Client Application"
Section 7.6, "Additional JavaSE Classes Provided by the ADF Mobile Client Framework"
ADF applications typically invoke custom methods defined on an application module or a view object in response to some event or action that occurs on a page. These custom method invocations are often declared in pages as EL expressions assigned to various component attributes, as illustrated by the EL expression "#{bindings.Foo.execute}"
in Example 7-1.
Example 7-1 Declaring a Method Using EL Expressions
<amc:commandButton text="Foo" id="commandButton1" actionListener="#{bindings.Foo.execute}"/>
This type of declarative invocation assumes that the platform on which the application executes binds dynamically and invokes methods by name rather than compiling the method invocation directly into the object code that executes at runtime.
On J2SE- and J2EE-based platforms, dynamic method invocation is enabled through Java reflection (java.lang.reflect
) classes which use underlying VM support to dynamically link to a method call by name. ADF Mobile client's J2ME platform, unlike J2SE- or J2EE-based platforms, does not have this VM support to implement Java reflection. Consequently, ADF Mobile client applications do not bind methods dynamically; they instead link methods statically at compile time.
Because the ADF Mobile client framework cannot rely on Java reflection to bind to methods dynamically, it requires the application to provide information about the method to be called. In addition, for the framework to call the method, it must call through a generic interface to code that is linked at compile time to the method call. The framework infrastructure accomplishes these through the bindings declaration in application metadata defined for the page and through the oracle.adfnmc.util.MethodDispatch
interface.
The ADF Mobile client framework simulates binding to methods dynamically by calling abstractly through MethodDispatch.invokeMethod
, passing information about the method to be called, and relying on the application to provide the concrete code that links the names to compile time method calls. MethodDispatch
should be implemented on each application module or view object implementation class that uses custom Java methods.
You can add custom methods using the overview editors for application modules or view objects as follows:
Add a method to the application module or view object.
Access the overview editor by either choosing Open from the context menu in the Application Navigator, or by double-clicking the application module or view object. For more information on using the overview editor, see "Creating and Modifying an Application Module" and "Generating Custom Java Classes for a View Object" in Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
Expose this method to the client interface.
Implement MethodDispatch.invokeMethod
on the application module or view object as illustrated in Example 7-2.
Example 7-2 Implementing the MethodDispatch Interface
public class MyVOImpl extends ViewObjectImpl implements MyVO, MethodDispatch { public String myCustomMethod(String param1, boolean param2) { // implementation... } public Object invokeMethod(String methodName, Object[] params) { if (methodName.equals("myCustomMethod")) { String param1 = (String)params[0]; boolean param2 = ((Boolean)params[1]).booleanValue()) return this.myCustomMethod(param1, param2); } } }
ADF Mobile client supports using Java to extend and customize the functionality delivered by the metadata of the standard business components. While you can employ many of the same techniques and high-level API calls that you use in standard ADF Faces applications, the target mobile device platforms impose constraints in the following areas when you develop ADF Mobile client applications:
Only the following APIs are available in this category:
Class.forName(String)
Class.newInstance()
All source code is compiled for compatibility with a JDK 1.3 JVM. As a consequence, there is no support for Java 5 language features, including:
Generics
Iterators
Annotations
Enumerations
In addition to missing language features, the supported target platforms also lack a number of classes used in developing JavaSE and JavaEE platforms, including JDBC for interfacing with relational databases and collections such as HashMap
and ArrayList
. To offset these gaps in functionality, ADF Mobile client provides its own implementations of these constructs, which augment the target platforms' base class libraries. However, because some target devices do not permit modifying the JVM bootclasspath, there is no provision for placing these implementations in the standard java.*
or javax.*
package hierarchies. You must instead import these classes from the alternate oracle.adfnmc.java.*
or oracle.adfnmc.javax.*
package hierarchies.
For example, instead of:
import java.sql.ResultSet; import java.util.HashMap;
Use:
import oracle.adfnmc.java.sql.ResultSet; import oracle.adfnmc.java.util.HashMap;
Then use the classes normally:
HashMap map = new HashMap(); map.put("Key", "Value"); ResultSet rs = preparedStatement.executeQuery();
Java source code can be used to extend the functionality of various business components, including entity objects, view objects, and application modules. Table 7-1 lists both the ADF Mobile client's supported and unsupported extension points.
Table 7-1 Supported and Unsupported Extension Points
Supported | Not Supported |
---|---|
Entity Object Class |
Entity Collection Class Entity Definition Class |
View Object Class View Row Class View Object Client Interface View Object Definition Class |
Service Data Object Class View Client Row Interface |
Application Module Class Application Module Client Interface Application Module Client Class |
Application Module Definition Class |
Not every method in BC4J is available for ADF Mobile client. To determine which methods are supported:
Use JDeveloper code completion and syntax highlighting features to determine what is supported at compile-time instead of repeatedly consulting a lengthy list of supported methods.
Consult Table 7-2 that lists the unsupported methods.
Table 7-2 Unsupported Methods
Class | Supported Methods |
---|---|
|
|
|
|
|
|
You can create and use managed beans (Mbeans) in an ADF Mobile client application to store additional data or to execute custom code. Adding an MBean to an ADF Mobile client application is similar to adding a bean to a standard Fusion Web application, except for the following differences:
The MBean class must implement oracle.adfnmc.util.MethodDispatch
or oracle.adfnmc.util.PropertiesDispatch
.
The MBean class must implement oracle.adfnmc.java.beans.PropertyValueChangeSource
.
The only valid scopes declared in an MBean are application
, backingBean
, and none.
The managed property default values not presently supported.
For more information, see "Using a Managed Bean in a Web Fusion Application" in Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
To add a managed bean:
In JDeveloper, click File then New.
Choose Java and then Java Class and then click OK.
In the Create Java Class dialog, enter a name for the Java class.
In the Implements field, click Add to open the Class and Package Browser and use it to locate oracle.adfnmc.util.MethodDispatch
.
Click Add to open the Class and Package Browser and use it to locate oracle.adfnmc.java.beans.PropertyValueChangeSource
.
Click OK.
Use the overview editor for the ADF Mobile client task flow to add this Java class as a managed bean as follows:
In the Application Navigator, select the task flow (typically MobileClient-task-flow.xml
), click the Overview tab and then click Managed Beans.
In the Managed Beans page, click New.
Enter a name for the managed bean.
Enter the name of the Java class created in Steps 1 through 5.
Add custom methods and properties to the Java class.
To add a custom property, declare the backing member variable for that property and then select Source and then Generate Accessors.
Select each member for which you wish to generate accessors, as illustrated in Figure 7-3.
Select Notify Listeners when property changes.
Because reflection is not supported in the J2ME version on some platforms such as BlackBerry, provide dispatch code if you want to invoke or access any of the methods or properties from EL. Example 7-3 illustrates using invokeMethod
.
The managed bean must implement oracle.adfnmc.util.MethodDispatch
. Because accessing properties and calling methods through EL expressions assumes that the platform on which the application executes binds dynamically and invokes methods by name rather than by compiling the method invocation directly into the object code that executes at runtime, this interface declares a single method, invokeMethod
, that must be implemented to resolve names to actual property accessors or method calls.
On J2SE- and J2EE-based platforms, dynamic method invocation is enabled through the use of the java.lang.reflect
classes which use underlying VM support to dynamically link to a method call by name. This is not the case for J2ME platforms, which lack the VM support required to implement the reflection classes. On this platform, methods can only be linked statically at compile time. The ADF Mobile client framework simulates binding to methods dynamically by calling abstractly through oracle.adfnmc.util.MethodDispatch.invokeMethod
, passing information about the method to be called, and relying on the application to provide the concrete code that links the names to compile-time method calls.
Note:
while the second argument toinvokeMethod
is a parameter list to be passed to the named method, with the exception of a "set" property accessor, this argument is not used when resolving a bean method using EL expressions. The ADF Mobile client EL syntax does not support an explicit parameter list when referencing a method. However, values can be passed indirectly to the method through object variable scopes, and accessed within the method implementation.oracle.adfnmc.util.PropertyDispatch
derives from MethodDispatch
and can be implemented to add support for type conversions for properties of types other than String
through the use of the getType(String)
method. This method returns the type of a property given its name. Because J2ME platforms do not support reflection, using EL expressions to reference these properties from certain UI components my require using the getType(String)
method. Example 7-3 provides a sample implementation of invokeMethod
and getType(String)
.
Note:
You must invokeinvokeMethod
regardless.oracle.adfnmc.java.beans.PropertyValueChangeSource
is the interface through which ADF Mobile client EL expressions register themselves as listeners on the objects that they reference, enabling all occurrences of the same expression to be updated when the underlying value to which they evaluate changes. The ADF Mobile client UI components rely on this notification mechanism to keep the view of the active form up to date when values referenced by EL expressions change in the application through normal interaction.
Although implementing this interface is not required to simply reference bean methods or properties through EL expressions, the rendering of any EL expressions in the active form that depend on values stored in the bean must be kept up to date if those values change.
JDeveloper can automatically generate the necessary code to source notifications from your bean's property accessors by selecting Notify listeners when property changes in the Generate Accessors dialog, illustrated in Figure 7-3.
Note:
You must manually declareimplements PropertyChangeSource
in your class. The generated code does not currently add this, and it is required for ADF Mobile client runtime support. Example 7-3 illustrates implements PropertyChangeSource.
You must also change the package in the imports declarations of PropertyChangeListener
, PropertyChangeSource
, and PropertyChangeSupport
from java.beans
to oracle.adfnmc.java.beans
.
Example 7-3 Using PropertyDispatch
package adfmc.managedbean; import oracle.adfnmc.component.MessageBox; import oracle.adfnmc.event.ClientEvent; import oracle.adfnmc.java.beans.PropertyChangeListener; import oracle.adfnmc.java.beans.PropertyChangeSource; import oracle.adfnmc.java.beans.PropertyChangeSupport; import oracle.adfnmc.java.sql.Timestamp; import oracle.jbo.domain.Number; import oracle.adfnmc.util.PropertyDispatch; // Instead of implementing MethodDispatch here, we are using // PropertyDispatch which derives from MethodDispatch. It adds the // getType method. This method allows you to return the correct types // for each expression so the type conversions can be invoked // automatically. // PropertyChangeSource allows you to fire notifications when your // member variables change so other components bound to the same // properties also get updated. public class Sample2 implements PropertyChangeSource, PropertyDispatch { private transient PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); public Sample2() { } private String prop1 = ""; private Number prop2 = new Number(0); private Timestamp prop3 = new Timestamp(0); private Boolean prop4 = Boolean.FALSE; private String prop5 = ""; public Object invokeMethod(String methodName, Object[] params) { if (methodName.equals("MyMethod")) { Object actionEvent = params[0]; this.MyMethod((ClientEvent)actionEvent); return null; } else if (methodName.equals("prop1")) { if (params.length == 0) { return this.getProp1(); } else { Object value = params[0]; this.setProp1((String)value); return null; } } else if (methodName.equals("prop2")) { if (params.length == 0) { return this.getProp2(); } else { Object value = params[0]; this.setProp2((Number)value); return null; } } else if (methodName.equals("prop3")) { if (params.length == 0) { return this.getProp3(); } else { Object value = params[0]; this.setProp3((Timestamp)value); return null; } } else if (methodName.equals("prop4")) { if (params.length == 0) { return this.getProp4(); } else { Object value = params[0]; this.setProp4((Boolean)value); return null; } } else if (methodName.equals("prop5")) { if (params.length == 0) { return this.getProp5(); } else { Object value = params[0]; this.setProp5((String)value); return null; } } return null; } // Note that you cannot use the java.bean namespace for these methods // and they must use the oracle.adfnmc versions. The implementations // are the same though. public void addPropertyChangeListener(PropertyChangeListener l) { propertyChangeSupport.addPropertyChangeListener(l); } public void removePropertyChangeListener(PropertyChangeListener l) { propertyChangeSupport.removePropertyChangeListener(l); } public void MyMethod(ClientEvent valueChangeEvent) { MessageBox.show("MyMethod fired!"); } public void setProp1(String prop1) { String oldProp1 = this.prop1; this.prop1 = prop1; propertyChangeSupport.firePropertyChange("Prop1", oldProp1, prop1); } public String getProp1() { return prop1; } public void setProp2(Number prop2) { Number oldProp2 = this.prop2; this.prop2 = prop2; propertyChangeSupport.firePropertyChange("Prop2", oldProp2, prop2); } public Number getProp2() { return prop2; } public void setProp3(Timestamp prop3) { Timestamp oldProp3 = this.prop3; this.prop3 = prop3; propertyChangeSupport.firePropertyChange("Prop3", oldProp3, prop3); } public Timestamp getProp3() { return prop3; } public void setProp4(Boolean prop4) { Boolean oldProp4 = this.prop4; this.prop4 = prop4; propertyChangeSupport.firePropertyChange("Prop4", oldProp4, prop4); } public Boolean getProp4() { return prop4; } public void setProp5(String prop5) { String oldProp5 = this.prop5; this.prop5 = prop5; propertyChangeSupport.firePropertyChange("Prop5", oldProp5, prop5); } public String getProp5() { return prop5; } // For each of the EL properties you can return a type. This allows // the framework to do automatic type conversions. If you only have // string types, this method isn't necessary. public Class getType(String propertyName) { if (propertyName.equals("prop1")) { return String.class; } else if (propertyName.equals("prop2")) { return Number.class; } else if (propertyName.equals("prop3")) { return Timestamp.class; } else if (propertyName.equals("prop4")) { return Boolean.class; } else if (propertyName.equals("prop5")) { return String.class; } return Object.class; } }
As described in Section 5.3.12, "Working with Resource Bundles," you define the resource bundle configuration through the Project Properties as shown in Figure 5-15. When creating the user interface, you define the string references using JDeveloper's Select Text Resource dialog, which, when completed, results the creation of EL in the UI components that reference these strings. For more information, see Section 6.13, "Localizing UI Components" and "Working with Resource Bundles" in Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework.
JDeveloper makes the complete ADF resource bundle containing localized strings available during application compilation and deployment. The resource bundle is translated to the format that is required by the run time. See also Section 8.6, "Deploying a Multi-Language ADF Mobile Client Application." For a list of country names and languages used in resource bundle files, see Appendix A, "Language Abbreviations."
ADF Mobile client supports the JavaSE ListResourceBundle
and PropertyResourceBundle
classes, but you cannot use these classes as you would in JavaSE or JavaEE. Specifically, you cannot import these classes from the java.util
. package as shown in Example 7-4 because they are not supported on mobile devices.
Example 7-4 Importing from the java.util Package
import java.util.ListResourceBundle; import java.util.PropertyResourceBundle;
Instead, import these resource bundle classes from oracle.adfmnc.java.util
as shown in Example 7-5.
Example 7-5 Importing from oracle.adfnmc.java.util Package
import oracle.adfnmc.java.util.ListResourceBundle; import oracle.adfnmc.java.util.PropertyResourceBundle;
You use these constructs in ADF Mobile client as you would in Java SE or Java EE environments. You can provide localization of selected String
resources using properties files that include settings appropriate to both non-localized and localized display. The names of the properties files distinguish localized and non-localized resources. For example, Example 7-6 illustrates the non-localized properties file called localizationStrings.properties
and Example 7-7 illustrates the localized settings in an English-only properties file called localizationString_en.properties
. The _en
locale identifier appended to the file name denotes that this properties file is English-only.
Example 7-6 Settings in a Non-Localized File, localizationStrings.properties
errorMsg=Problem has occurred greeting=To Whom It May Concern
Example 7-7 shows the settings in a localized, English-only properties file.
Example 7-8 illustrates the Java code that accesses these properties. The non-localized line always returns a Problem has occurred string. The localized line (Hey There! ) is returned on English language-supported platforms, while To Whom It May Concern is returned on all other locales.
Example 7-8 Accessing Properties
ResourceBundle resourceBundle = ResourceBundle.getBundle("some.package.foo"); System.out.println(resourceBundle.getString("errorMsg"); // non-localized; always returns "Problem has occurred" System.out.println(resourceBundle.getString("greeting"); // localized. returns "Hey there" on English platforms; "To Whom It May Concern" on all other locales
These resource bundles are also used implicitly at run time for attribute control hints. For example, if there is an attribute in a ViewObject
named PersonID
and PersonID=Custom Label
is defined in the Model project's resource bundle, then at run time, whenever this attribute is displayed, it uses the custom label for the label property rather than defaulting to the name of the attribute.
ADF Mobile client supports localization by resolving XLIFF (XML Localization Interchange File Format) resource bundles in addition to its support of .properties
resource bundles. After ADF Mobile client imports the resource bundles from the base (server) application and resolves them, it populates attributes with the appropriate values taken from the JAR of the base application.
Figure 7-5 shows the format of an XLF bundle called localizationBundle_de.xml
, which is in the German language (as noted by _de
).
The following examples demonstrate how ADF Mobile client supports localization by resolving a resource bundle in English (the default) and one in German.
Example 7-9, the source code for an attribute called Starttime
, illustrates the results of importing a German language resource bundle named localizationBundle_de
from the base (server) application's JAR file: within the LABEL
tag for Starttime
attribute, ADF Mobile client retrieved the value for ResID
is defined as ${adfBundle['localization.localizationBundle_de'][localization.Caldroptest.Starttime_LABEL']}
from the base application's JAR.
Example 7-9 The Starttime Attribute
<Attribute Name="Starttime" ColumnName="STARTTIME" SQLType="TIMESTAMP" Type="oracle.jbo.domain.Date" ColumnType="DATE" TableName="CALDROPTEST"> <DesignTime> <Attr Name="_DisplaySize" Value="7"/ </DesignTime> <Properties> <SchemaBasedProperties> <LABEL ResId=${adfBundle['localization.localizationBundle_de'][localization.Caldroptest.Starttime_LABEL']} </SchemaBasedProperties> </Properties> </Attribute>
As shown in Figure 7-5, viewing the attribute displayed in the editor (accessed through the overview editor for the entity object), verifies that ADF Mobile client has retrieved the correct string value from the German language file, as the Label Text value is defined as Startzeit
.
In addition to the German language resource bundle used for the Startzeit
attribute, the Endtime
attribute uses the default resource bundle, which is in English. The value of LABEL
in Figure 7-5 shows that ADF Mobile client likewise imported the resource bundle from the JAR, although this one is the default (${adfBundle['localization.localizationBundle']['localization.Caldroptest.Endtime_LABEL']}
).
Example 7-10 The Endtime Attribute
<Attribute Name="Endtime" ColumnName="ENDTIME" SQLType="TIMESTAMP" Type="oracle.jbo.domain.Date" ColumnType="DATE" TableName="CALDROPTEST"> <DesignTime> <Attr Name="_DisplaySize" Value="7"/ </DesignTime> <Properties> <SchemaBasedProperties> <LABEL ResId=${adfBundle['localization.localizationBundle']['localization.Caldroptest.Endtime_LABEL']} </SchemaBasedProperties> </Properties> <Attribute>
As shown in Figure 7-6, the attribute editor displays the Label Text value as End Time
.
After deployment to a device, such as BlackBerry smartphone in Figure 7-7, the application displays the column labels derived from the German language and default, English language, resource bundles.
Data bindings - "#{bindings.*}"
Application global variable scope - "#{applicationScope.*}"
Note:
applicationScope
variables, such as beans, can be called either with the applicationScope
prefix (#(applicationScope.Bean.method)
) or without #(Bean.method)
.Sync Context - "#{syncContext.*}"
Security Context - "#{securityContext.*}"
Device Context - "#{device.*}"
EL Expression strings can be evaluated programmatically from Java code to resolve property values and invoke methods. EL Expressions are represented at runtime as objects that implement either the ValueExpression
or MethodExpression
interface. Expression objects are created by passing the EL expression string and some type information to factory methods on an ELContext, as shown in Example 7-11 and Example 7-12.
Example 7-11 illustrates using the ValueExpression
interface to get or set a named value identified by an EL expression string.
Example 7-11 Using the ValueExpression Interface
import oracle.adfnmc.el.ValueExpression; import oracle.adfnmc.el.impl.SimpleContext; ... Class expectedType = String.class; String expressionStr = "#{applicationScope.testBean.testProperty}"; ValueExpression expr = SimpleContext.getValueExpression(expressionStr, expectedType); String value = (String) testBeanExpr.getValue(); testBeanExpr.setValue("newValue");
Example 7-12 illustrates using the MethodExpression
interface to invoke a method identified by an EL expression string:
Example 7-12 Using the MethodExpression Interface
import oracle.adfnmc.el.impl.SimpleContext; import oracle.adfnmc.el.MethodExpression; ... // invoke "String testMethod(String param)" on TestBean.java instance Class expectedReturnType = String.class; Class[] expectedParamTypes = new Class[] { String.class }; String expressionStr = "#{applicationScope.testBean.testMethod}"; MethodExpression expr = SimpleContext.getMethodExpression(expressionStr, expectedReturnType, expectedParamTypes); String retVal = (String)expr.invoke(new Object[] { "param1Value" });
Method parameters are not declared directly in EL method expression strings. The parameter values may come from other areas, such as EL value expressions or data members in a bean. It is assumed that the caller will have their actual values available to pass at invocation.
Table 7-3 lists JavaSE classes provided by ADF Mobile client.
Table 7-3 Additional JavaSE Classes
JavaSE Class | ADF Mobile Client Equivalent |
---|---|
java.lang.Math |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
java.util.SortedSet |
oracle.adfnmc.java.util.SortedSet |
|
|
|
|
|
|
|
|
|
|
|
This API is compatible, but it does not maintain weak reference semantics. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
o |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
j |
|
|
|
|
o |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|