Oracle JDeveloper Tip

Supporting Global Custom Framework Extension Interfaces

Author: Steve Muench, ADF Development Team
Date: July 22, 2004

Abstract

It has always been possible for an ADF application module and view object to expose custom client interfaces with extended methods. However, this has always been possible to do only on a component-by-component basis. In JDeveloper 10g (version 9.0.5.2) and beyond, developers using ADF Business Components can extend the framework base components ApplicationModule, ViewObject, and ViewRow to support global custom interfaces. This makes it much easier to expose common functionality that is destined to be available for client invocation in a global way. This article describes the steps required to implement the feature in your applications.


NOTE:

This article is valid only for ADF Business Components in JDeveloper 10g (version 9.0.5.2) and beyond.



NOTE:

You can download the CustomInterfaceExample.zip workspace containing the example project that illustrates this feature in use. You'll need a JDeveloper database connection named scott defined for the familiar SCOTT schema, and a JDeveloper application server connection named localoc4j to try the example in both 2-tier and 3-tier deployment styles.


Extending Framework Base Classes

One of the most powerful features of framework-based development is the ability to extend the framework base classes in a way that is specific to your needs. The Customizing the Default Framework Behavior section in the whitepaper accompanying the ADF Toy Store Demo explains the numerous examples of framework customization that are part of the demo's implementation.

It's a best practice that most every customer I know uses. Even if you might not currently need to add any custom functionality in the base framework at this moment in time, it good in any event to create yourself a custom framework extension class and use it in your development instead of the "raw" base classes. This insures that when some functionality does arise that all of your components suddenly would benefit from, you have a convenient class to add that functionality into. As an example, a central framework team within our own Oracle Applications division extends virtually all of the ADF Business Components base classes to add custom functionality that is required by the many teams building the E-Business Suite self-service applications.

Previous Steps to Expose Framework Extension Methods to Clients

One aspect of framework extensions has been problematic before the JDeveloper 10g (version 9.0.5.2) release has been making custom framework base class methods available in a tier-independent way to be called by clients. That is, while you could easily create yourself a MyCompanyAppModuleImpl class that extended the base ApplicationModuleImpl framework class to add new features, it was not easy to have clients be able to invoke the new methods. In order to do so, you needed to perform the following steps for each ApplicationModule in which these features needed to be accessed by clients:

  1. Have your com.yourcompany.SomeAppModule component extend MyCompanyAppModuleImpl
  2. Provide trivial overrides in SomeAppModule for each method you wanted to expose from the superclass MyCompanyAppModuleImpl.
  3. Selecting those methods for inclusion on the client interface SomeAppModule on the Client Interface panel of the ApplicationModule editor.

These steps resulted in creation of a com.yourcompany.common.SomeAppModule interface that clients could use at runtime to call the exposed custom methods by casting their ApplicationModule instance to its custom interface.

The process was the same for ApplicationModules, ViewObjects and ViewRows. While possible, it was tedious at best if these features needed to be exposed on a large number of components in your applications.

Simpler Approach Now Possible with ADF 9.0.5.2

In the JDeveloper 10g (version 9.0.5.2) release, it's now possible to expose base framework extension methods on your own custom interface in a global way on your components to avoid the tedium described above. We'll describe the steps for an ApplicationModule as an example, but they are the same for ViewObject and ViewRow.

Assume we have a test.fwk.ExtraAMFeaturesImpl class that extends oracle.jbo.server.ApplicationModuleImpl and we want to expose two custom methods to clients in a global way from this class:

public void doFeatureOne(String arg);
public int anotherFeature(String arg);

Here are the steps to allow a com.mycompany.SomeModule component to invoke these two global custom methods on your test.fwk.ExtraAMFeaturesImpl class.

First, follow these steps to expose a custom interface for your two client methods on your framework extension class:

  1. Create a custom interface that contains the methods you would like to expose globally on our application module components. For our scenario, it looks like this:

    package test.fwkext;
    /**
     * NOTE: This does not extend the oracle.jbo.ApplicationModule interface.
     */
    public interface ExtraAMFeatures  {
      public void doFeatureOne(String arg);
      public int anotherFeature(String arg);
    }

    Notice that the interface does not extend the oracle.jbo.ApplicationModule interface.

  2. Modify your test.fwk.ExtraAMFeaturesImpl application module framework extension class to implement this new ExtraAMFeatures interface.

    package test.fwkext;
    import oracle.jbo.server.ApplicationModuleImpl;

    public class ExtraAMFeaturesImpl extends ApplicationModuleImpl
           implements ExtraAMFeatures {
      public void doFeatureOne(String arg) {
        System.out.println("## Called Extra ApplicationModule Feature ##");
      }
      public int anotherFeature(String arg) {
        return 1;
      }
    }
  3. Rebuild your project.

    The ADF wizards will only "see" your interfaces if they have been successfully compiled.

With the above out of the way, the following two steps are required to expose this custom interface on a given ApplicationModule component. Here we explain the steps for a SomeModule component.

  1. Make sure that your SomeModule component is based on your test.fwk.ExtraAMFeaturesImpl framework extension.

    To do this, open the ApplicationModule Editor for SomeModule and visit the Java tab. Click on the (Class Extends...) button and m ake sure the class name in the Object field reads test.fwk.ExtraAMFeaturesImpl.


    NOTE: If you had to change the base class name in this step, before proceeding to the next step, close the dialog by pressing the (OK) button, and then re-edit the application module again before proceding to the next step. This makes certain that the wizard correctly "sees" the newly generated classes resulting from your change of base class.

  2. Indicate that you want the test.fwkext.ExtraAMFeatures interface to be one of the custom interfaces clients can use with your component.

    To do this, with the Application Module editor still open, visit the Client Interface panel. Click on the (Interfaces...) button. Shuttle the test.fwkext.ExtraAMFeatures interface from the Available to the Selected list, then press (OK) .

  3. Insure that at least one method appears in the Selected list on the Client Interface panel.


    CAVEAT: If you have no other custom methods to add to the interface of the current Application Module, due to Bug 3784776, in 9.0.5.2 you still need to add at least one method into the Selected list to get the ADF Business Components code generate to work correctly, even if it means redundantly selecting a method whose implementation comes from the component's base class. This insures that the custom interface gets created correctly and can be used in the client as expected.

When you dismiss the Application Module editor you're done.

The basic steps are the same for exposing methods on a ViewObjectImpl framework extension class, as well as for a ViewRowImpl extension class. Assuming that you have:

  • test.fwkext.ExtraVOFeaturesImpl that extends ViewObjectImpl and implements test.fwkext.ExtraVOFeatures interface, and
  • test.fwkext.ExtraVORowFeaturesImpl that extends ViewRowImpl and implements test.fwkext.ExtraVORowFeatures interface

Then, to setup the ViewObject custom interface exposure you would:

  1. Visit Java panel of the ViewObject Editor and click (Class Extends...) to specify test.fwkext.ExtraVOFeaturesImpl as the Object class.


    NOTE: If you had to change the base class name in this step, before proceeding to the next step, close the dialog by pressing the (OK) button, and then re-edit the view object again before proceding to the next step. This makes certain that the wizard correctly "sees" the newly generated classes resulting from your change of base class.

  2. Visit the Client Interface panel of the ViewObject Editor and click (Interfaces...) to select the test.fwkext.ExtraVOFeatures interface.

CAVEAT:

The same caveat mentioned above for Application Modules — about having at least one method in the Selected list when you are trying to expose a base interface — applies for View Object custom base interfaces as well in JDeveloper 10g version 9.0.5.2.


And to setup the ViewRow custom interface exposure you would:

  1. Visit Java panel of the ViewObject Editor and click (Class Extends...) to specify test.fwkext.ExtraVORowFeaturesImpl as the Row class.
  2. Make sure that you have generated a View Row Class.


    NOTE: If you had to change the base class name in step 1, before proceeding to the next step, close the dialog by pressing the (OK) button, and then re-edit the view object again. This makes certain that the wizard correctly "sees" the newly generated classes resulting from your change of base class.

  3. Visit the Client Row Interface panel of the ViewObject Editor and click (Interfaces...) to select the test.fwkext.ExtraVORowFeatures interface.

CAVEAT:

The same caveat mentioned above for Application Modules — about having at least one method in the Selected list when you are trying to expose a base interface — applies for View Object Row custom base interfaces as well in JDeveloper 10g version 9.0.5.2. If you are exposing the attribute getter methods on the current components base interface, then you won't need to add and then remove a redundant method from the interface.


Insuring the Correct Contents of the Common Client JAR

When you create an EJB Session Bean deployment profile for your application module — by selecting your application module and choosing Business Components Deployment... from the right-mouse menu — ADF is smart enough to create deployment profile filters for its own client interfaces and domains so that only the classes that the client layer absolutely requires end up in the ModelEjbCommon.jar. However, it doesn't have knowledge about your package structure for your own custom base classes, so you need to give it a little help to make sure there are no "Impl" classes being packaged into the client-side "Common" JAR.

After creating myself an EJB Session Bean deployment profile for my TestModule in the example project, I did the following to insure that my custom base class "Impl" files do not end up in the client-only Common JAR.

  1. Expanded the ModelEJB.bcdeploy deployment profile.
  2. Selected ModelEJBCommon.deploy and select Properties... from the right-mouse menu.
  3. Clicked on the Filters panel and expand the test and fwkext folders.
  4. Unchecked the checkbox next to ExtraAMFeaturesImpl.class, ExtraVOFeaturesImpl.class, and E xtraVORowFeatures.class.

Then, when I deployed the module, the ModelEJBCommon.jar ends up getting only the interfaces and custom domains (if there were any) that are needed on the client in a three-tier deployment.

Calling the Base Interface Methods from a Client

The CustomInterfaceExample.zip workspace comes with two simple client projects View2Tier and View3Tier. Both projects contain the same runnable PanelDeptView.java class that illustrates a basic runnable Swing panel with a button whose event handler invokes all of the exposed methods on custom interfaces from the ExtraAMFeatures, ExtraVOFeatures, and ExtraVORowFeatures custom interfaces.

The (Test Custom Interfaces) button event handler code looks like this:

  private void jButton1_actionPerformed(ActionEvent e) {
    DCJboDataControl dc = (DCJboDataControl)panelBinding.getDataControl();
    ApplicationModule am = dc.getApplicationModule();
    if (am instanceof ExtraAMFeatures) {
      ExtraAMFeatures amEx = (ExtraAMFeatures)am;
      amEx.doFeatureOne("foo");
      System.out.println(amEx.anotherFeature("bar"));
    }
    ViewObject vo = am.findViewObject("DeptView");
    if (vo instanceof ExtraVOFeatures) {
      ExtraVOFeatures voEx = (ExtraVOFeatures)vo;
      voEx.doFeatureOne("foo");
      System.out.println(voEx.anotherFeature("bar"));
    }
    /*
     * Alternative technique to get custom VO interface
     * that works for sync-mode = Batch.
     */
    ViewObject vo2 = dc.findCustomViewObject("DeptView",
                       ExtraVOFeatures.class.getName());
    if (vo2 instanceof ExtraVOFeatures) {
      ExtraVOFeatures vo2Ex = (ExtraVOFeatures)vo;
      vo2Ex.doFeatureOne("foo2");
      System.out.println(vo2Ex.anotherFeature("bar2"));
    }
    Row row = vo.first();
    if (row instanceof ExtraVORowFeatures) {
      ExtraVORowFeatures rowEx = (ExtraVORowFeatures)row;
      rowEx.doFeatureOne("foo");
      System.out.println(rowEx.anotherFeature("bar"));
    }  
  }

NOTE:

The sample client code would be the same for accessing these methods from inside a Struts action class in an ADF-based Web application.


The View2Tier project has its TestModuleDataControl properties set to use the TestModuleLocal configuration. The View3Tier project has the TestModuleDataControl properties set to use the TestModule9iAS configuration. Both projects use a Sync Mode of Immediate.


CAVEAT:

Note that due to Bug 3784922, I am using the Sync Mode of Immediate on my TestModuleDataControl in the View3Tier project, since the custom base interfaces functionality is not currently working correctly with the default Batch sync mode for a 3-tier deployment. To see this setting:

  • Select the DataBindings.cpx file in the View project in the Application Naviator .
  • Click on the TestModuleDataControl in the Structure Window
  • Look at the Sync Mode property in the Property Inspector .

I have defined a project-level library in the View2Tier project named ModelEJBMiddleTierJAR that points to the ModelEJBMT.jar created by the EJB Session Bean business component deployment profile that we discussed in the previous section. Likewise, in the View3Tier project, I created a project-level library named ModelEJBCommonJAR pointing to the ModelEJBCommon.jar created by the same deployment profile. This ensures that the correct model layer classes — or just interfaces and generated client proxy classes for the 3-tier case — are in the class path at design time and runtime.

Running the PanelDeptView class in the View2Tier project runs both client and server classes in the same Java VM. When you click on the (Test Custom Interfaces) button, it should produce the following output to the JDeveloper Log window:

## Called Extra ApplicationModule Feature ##
1
## Called Extra View Object Feature ##
2
## Called Extra View Object Feature ##
2
## Called Extra View Row Feature ##
3

In the local-mode configuration, both client-side and server-side messages print out to the same console window.

If you deploy the ModelEjb.deploy in the Model project to an external OC4J instance having a JDeveloper application server connection name of localoc4j, then you can try running the PanelDeptView in the View3Tier project to try the application in 3-tier mode as well.


TIP:

To start an external OC4J instance that is preconfigured to run ADF-based applications — which the oc4j_extended.zip OC4J "Standalone" download from OTN is not due to wanting to keep the download size very small — simply run the <JDEVHOME>/jdev/bin/start_oc4j.bat script or start_oc4j shell script on Unix in the same directory.


Running the PanelDeptView class in the View3Tier project runs the client UI in the JDeveloper embedded Java VM while the server classes are running in a different external OC4J Java VM outside JDeveloper. When you click on the (Test Custom Interfaces) button, it should produce the following output to the JDeveloper Log window:

1
2
2
3

and the following output to the external OC4J console window:

## Called Extra ApplicationModule Feature ##
## Called Extra View Object Feature ##
## Called Extra View Object Feature ##
## Called Extra View Row Feature ##

Conclusion

We hope this new feature comes in handy in your applications!

false ,,,,,,,,,,,,,,,