|
Supporting Global Custom Framework Extension Interfaces
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:
- Have your
com.yourcompany.SomeAppModule
component extend MyCompanyAppModuleImpl
- Provide trivial overrides in
SomeAppModule for each method you
wanted to expose from the superclass
MyCompanyAppModuleImpl.
- 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:
-
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.
-
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;
}
}
-
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.
-
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 make 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. |
-
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).
-
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:
-
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. |
- 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:
- Visit Java panel of the
ViewObject Editor and click (Class
Extends...) to specify
test.fwkext.ExtraVORowFeaturesImpl as the
Row class.
-
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. |
- 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.
- Expanded the
ModelEJB.bcdeploy deployment profile.
- Selected
ModelEJBCommon.deploy and select
Properties... from the right-mouse
menu.
- Clicked on the
Filters panel and expand the
test and
fwkext folders.
- Unchecked
the checkbox next to
ExtraAMFeaturesImpl.class,
ExtraVOFeaturesImpl.class, and
ExtraVORowFeatures.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!
|