Skip Headers
Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers
10g Release 3 (10.1.3.0)
B25947-01
  Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
 
Next
Next
 

8.5 Working Programmatically with an Application Module's Client Interface

After publishing methods on your application module's client interface, you can invoke those methods from a client.

8.5.1 How to Work Programmatically with an Application Module's Client Interface

To work programmatically with an application module's client interface, do the following:

  • Cast ApplicationModule to the more specific client interface.

  • Call any method on the interface.


Note:

For simplicity, this section focuses on working only with the custom application module interface; however; the same downcasting approach works on the client to use a ViewObject interface as a view object interface like ServiceRequests or a Row interface as a custom view row interface like ServiceRequestsRow.

Example 8-9 illustrates a TestClientCustomInterface class that puts these two steps into practice. You might recognize it from Section 6.8, "Working Programmatically with Entity Objects and Associations" where you tested some example application module methods from within the main() method of the SRServiceImpl class itself. Here it's calling all of the same methods from the client using the SRService client interface.

The basic logic of the example follows these steps:

  1. Acquire the application module instance and cast it to the more specific SRService client interface.


    Note:

    If you work with your application module using the default ApplicationModule interface in the oracle.jbo package, you won't have access to your custom methods. Make sure to cast the application module instance to your more specific custom interface like the SRService interface in this example.

  2. Call findRequestStatus() to find the status of service request 101.

  3. Call findServiceRequestTechnician() to find the name of the technician assigned to service request 101.

  4. Call updateRequestStatus() to try updating the status of request 101 to the illegal value Reopened.

  5. Call createProduct() to try creating a product with a missing product name attribute value, and display the new product ID assigned to it.

Example 8-9 Using the Custom Interface of an Application Module from the Client

package devguide.client;
import devguide.model.common.SRService;
import oracle.jbo.JboException;
import oracle.jbo.client.Configuration;
public class TestClientCustomInterface {
  public static void main(String[] args) {
    String        amDef = "devguide.model.SRService";
    String        config = "SRServiceLocal";
    /*
     * This is the correct way to use application custom methods
     * from the client, by using the application module's automatically-
     * maintained custom service interface.
     */
    // 1. Acquire instance of application module, cast to client interface
    SRService service = 
      (SRService)Configuration.createRootApplicationModule(amDef,config);
    // 2. Find the status of service request 101
    String status = service.findServiceRequestStatus(101);
    System.out.println("Status of SR# 101 = " + status);
    // 3. Find the name of the technician assigned to service request 101
    String techName = service.findServiceRequestTechnician(101);
    System.out.println("Technician for SR# 101 = " + techName);
     try {
       // 4. Try updating the status of service request 101 to an illegal value
       service.updateRequestStatus(101,"Reopened");
     }
     catch (JboException ex) {
       System.out.println("ERROR: "+ex.getMessage());
     }
     long id = 0;
     try {
       // 5. Try creating a new product with a missing required attribute
       id = service.createProduct(null,"Makes Blended Fruit Drinks");
     }
     catch (JboException ex) {
       System.out.println("ERROR: "+ex.getMessage());
     }
     // 6. Try creating a new product with a missing required attribute
     id = service.createProduct("Smoothie Maker","Makes Blended Fruit Drinks");
     System.out.println("New product created successfully with id = "+id);
    Configuration.releaseRootApplicationModule(service,true);
  }
}

8.5.2 What Happens When You Work with an Application Module's Client Interface

If the client layer code using your application module is located in the same tier of the J2EE architecture, this configuration is known as using your application module in "local mode." In local mode, the client interface is implemented directly by your custom application module Java class. Typical situations that use an application module in local mode are:

  • A JavaServer Faces application, accessing the application module in the web tier

  • A JSP/Struts application, accessing the application module in the web tier

  • A Swing application, accessing the application module in the client tier (2-tier client/server style)

In contrast, when the client layer code accessing your application module is located in a different tier of the J2EE architecture, this is known as using the application module in "remote mode." In remote mode, the generated client proxy class described above implements your application module service interface on the client side and it handles all of the communications details of working with the remotely-deployed application module service. The typical situation that uses "remote mode" is a thin-client Swing application accessing the application module on a remote application server.

A unique feature of ADF Business Components is that by adhering to the best-practice interface-only approach for working with client service methods, you can be sure your client code works unchanged regardless of your chosen deployment mode. Even if you only plan to work in "local mode", it is still the best practice in the J2EE development community to adopt an interface-based approach to working with your services. Using application modules, it's extremely easy to follow this best practice in your applications.


Note:

Whether you plan to use your application modules in local deployment mode or remote mode, as described in Section 8.4.4, "What You May Need to Know About Method Signatures on the Client Interface", the JDeveloper design time enforces that your custom interface methods use Serializable types. This allows you to switch at any time between local or remote deployment mode, or to support both at the same time, with no code changes.

8.5.3 How to Access an Application Module Client Interface

The Configuration class in the oracle.jbo.client package makes it very easy to get an instance of an application module for testing. You've seen it used in numerous test client programs in this guide, and you'll see it again in the chapter on testing your application module services as part of the JUnit regression testing fixture. Because it is easy, however, it is tempting for developers to use its createRootApplicationModule() and releaseApplicationModule() methods everywhere they want to access an application module.

However, for web applications you should resist this temptation because there is an even easier way.

8.5.3.1 How to Access an Application Module Client Interface in a JSF Web Application

When working with JSF or Struts/JSP applications using the ADF Model layer for data binding, JDeveloper configures a servlet filter in your ViewController project called the ADFBindingFilter. It orchestrates the automatic acquisition and release of an appropriate application module instance based on declarative binding metadata, and insures that the service is available to be looked up as a data control. You'll learn more about the ADF BindingContext and data controls in later chapters, however here it's enough to remember that you can access the application module's client interface from this BindingContext. Since the BindingContext is available during each web page request by referencing the request-scoped attribute named data, you can reference the binding context in a JSF managed bean.

For instance, if you want to access the custom interface of the devguide.model.SRService application module, follow these basic steps shown in Example 8-10:

  1. Access the JSF FacesContext.

  2. Create value binding for the #{data} EL expression.

  3. Evaluate the value binding, casting the result to BindingContext.

  4. Find the data control by name from the BindingContext .

  5. Access the application module data provider from the data control.

  6. Cast the application module to its client interface.

  7. Call any method on the client interface.

Example 8-10 Accessing the Application Module Client Interface in a JSF Backing Bean

package demo.view;
import devguide.model.common.SRService;
import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;
import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCDataControl;
import oracle.jbo.ApplicationModule;
public class YourBackingBean {
  public String commandButton_action() {
    // 1. Access the FacesContext
    FacesContext fc = FacesContext.getCurrentInstance();
    // 2. Create value binding for the #{data} EL expression
    ValueBinding vb = fc.getApplication().createValueBinding("#{data}");
    // 3. Evaluate the value binding, casting the result to BindingContext
    BindingContext bc = (BindingContext)vb.getValue(fc);
    // 4. Find the data control by name from the binding context
    DCDataControl dc  = bc.findDataControl("SRServiceDataControl");
    // 5. Access the application module data provider
    ApplicationModule am = (ApplicationModule)dc.getDataProvider();
    // 6. Cast the ApplicationModule to its client interface
    SRService service    = (SRService)am;
    // 7. Call a method on the client interface
    service.doSomethingInteresting();
    return "SomeNavigationRule";
  }
}

The SRDemo application includes a JSFUtils class that encapsulates steps of evaluating an EL expression using a JSF value binding, and you can use the dot notation in an EL expression to chain method invocations together on successive beans and to look up beans in maps. So, putting these two ideas together, you can reduce the above steps to the single line like:

// Access the SRService custom interface with a single EL expression
SomeService service = (SomeService)JSFUtils.resolveExpression("#{data.SRServiceDataControl.dataProvider}");

Note:

ISection 10.3.2, "How to Change the Data Control Name Before You Begin Building Pages" explains how to rename the data control for an application module. If, as done in the SRDemo application, you use the technique described there to rename the data control for the SRService from the default name SRServiceDataControl to the shorter SRService name that matches the name of the application module itself, then the line of code above becomes the following:
// Access SRService custom interface with a single EL expression
// NOTE: SRService app module data control renamed to "SRService"
SomeService service = (SomeService)JSFUtils.resolveExpression(
                                 "#{data.SRService.dataProvider}");

8.5.3.2 How to Access an Application Module Client Interface in a JSP/Struts Web Application

If you use Struts and JSP for your view and controller layers, you can access the BindingContext and your application module custom interface from your custom PageController using code like what you see in Example 8-11. Notice that you can directly cast the result of getDataProvider() to the application module client interface without first needing to retrieve it as ApplicationModule.

Example 8-11 Accessing the Application Module Client Interface in ADF Page Controller

package demo.view;
import devguide.model.common.SRService;
import oracle.adf.controller.v2.context.LifecycleContext;
import oracle.adf.controller.v2.lifecycle.PageController;
import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCDataControl;
public class YourPageController extends PageController {
  public void prepareModel(LifecycleContext lcContext) {
    super.prepareModel(lcContext);
    BindingContext bc = lcContext.getBindingContext();
    DCDataControl  dc = bc.findDataControl("SRServiceDataControl");
    SRService service = (SRService)dc.getDataProvider();
    service.doSomethingInteresting();
  }
}

8.5.3.3 How to Access an Application Module Client Interface in an ADF Swing Application

If you use Swing to create desktop-fidelity applications, you can access the BindingContext and your application module custom interface from inside your Swing panels using code like what you see in Example 8-12.

Example 8-12 Accessing the Application Module Client Interface in ADF Swing Panel

package demo.view.panels;
import devguide.model.common.SRService;
import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCDataControl;
// etc.
public class YourPanel extends JPanel implements JUPanel {
  // etc.
  private void jButton1_actionPerformed(ActionEvent e) {
    BindingContext bc = getPanelBinding().getBindingContext();
    DCDataControl dc = bc.findDataControl("SRServiceDataControl");
    SRService service = (SRService)dc.getDataProvider();
    service.doSomethingInteresting();
  }
}