Thursday, September 25, 2014

ADF - Named Bind Variable Accessors Do Not Follow Naming Convention

When you generate a custom Java class for your view object, you can choose to "Include bind variable accessors":

Select Java Options Dialog
Select Java Options

JDeveloper will automatically add get/set methods as applicable for all the named bind variables of the view object. It's annoying that these accessors do not follow the standard naming conventions in that they do not automatically capitalize the first letter of the bind variable name. For example, if the view object EmployeeView defines a bind variable with the name "firstNameVariable", then the accessors will be like this:

public void setfirstNameVariable(String value);
public String getfirstNameVariable();

To make it follow the naming convention, you can manually edit the generated code to fix the names. Beware that whenever you regenerate the source code, you have to fix it again.

You can also choose to name your bind variables with an initial capital letter. That makes your accessors look better. Although initial capital letters also break the conventions for variable names, considering that ADF also use initial capital letters in attribute names for view and entity objects, this approach seems better than the first one, before JDeveloper fix this issue.

Friday, September 19, 2014

ADF - View Link Accessor Type and Cardinality

A view link associates two view objects to form a master-detail relationship. A view link accessor specifies an accessor attribute by which a view row at one end of a master-detail relationship specified by a view link can access the related view row or rows at the other end of the relationship. When you select to generate the custom view row class for the view object with an accessor, JDeveloper will uses the accessor's name to generate the corresponding view link accessor method, a getter method in the view row class.

By default, JDeveloper generates the view link accessor type and the corresponding view link accessor method return type with respect to the cardinality of the view link. For a "many" side of a view link, the view link accessor type will be "oracle.jbo.RowIterator"; for a "one" side, the view link accessor will have the type of "oracle.jbo.Row". This default behavior is acceptable in a majority of cases. For example:

View Object: DepartmentView

  <ViewLinkAccessor
    Name="EmployeesView"
    ViewLink="model.views.links.EmpToDeptLink"
    Type="oracle.jbo.RowIterator"
    IsUpdateable="false"/>

View Object: EmployeeView

  <ViewLinkAccessor
    Name="DepartmentView"
    ViewLink="model.views.links.EmpToDeptLink"
    Type="oracle.jbo.Row"
    IsUpdateable="false"/>

Sometimes, you may want to change this default behavior. In my case, I have a one-to-one master-detail composition relationship between UserView and ContactInfoView. For a new user, once a new user view row is created, a linked contact information view row is required to be created. In the UserView, the view link accessor for the ContactInfoView is defined by default as the following:

  <ViewLinkAccessor
    Name="ContactInfoView"
    ViewLink="model.views.links.UserToContactInfoLink"
    Type="oracle.jbo.Row"
    IsUpdateable="false"/>

I want the view link accessor type to be "oracle.jbo.RowIterator", so that from the user view row, I can use the accessor to create the associated contact information view row.

Fortunately, we can manually change the accessor type from "oracle.jbo.Row" to "oracle.jbo.RowIterator" in the source code of the view object:

View Object: UserView

  <ViewLinkAccessor
    Name="ContactInfoView"
    ViewLink="model.views.links.UserToContactInfoLink"
    Type="oracle.jbo.RowIterator"
    IsUpdateable="false"/>

In case you have already generated the custom view row class, you can manually fix the return type of the view link accessor method.

Now, with this view accessor, I can create contact information view row from a user view row with the code like this:

  userViewRow.getContactInfoView().createRow();


Wednesday, September 17, 2014

ADF - Enable Oracle Diagnostic Logger for ADF Request

Oracle ADF and JDeveloper have a great feature that allows us to view ADF event messsages in a hierarchical view. Specifically, it's the By ADF Request page of the Oracle Diagnostic Log Analyzer.



A wonderful tool, but it's not there by default. If you select By ADF Request, and the search returns no result, the message list displays nothing, Here's how to enable this feature.

The magic is the "oracle.adfdiagnostics" logger. You have to configure this logger to an ODL log level that is below NOTIFICATION:16 or a Java log level that is not more restrictive than CONFIG. This particular logger will generate messages for various ADF events that enables the hierarchical view of the ADF lifecycle events.



Resources:

Tuesday, September 16, 2014

ADF - ClassNotFoundException: oracle.jbo.jbotester.jdevx.ConnectionDialog

Recently, I got a brand new MacBook Pro with OS X 10.9.4 (Mavericks). I installed Java Platform (JDK) 8u20 and JDeveloper 12c (12.1.3.0.0). Both are the latest versions from Oracle.

Unfortunately, when I tried to test my application modules with ADF Model Tester, I got the exception with the following stack trace:

oracle.jbo.jbotester.app.ErrorHandler$ExceptionWrapper: JBO-29000: Unexpected exception caught: java.lang.ClassNotFoundException, msg=oracle.jbo.jbotester.jdevx.ConnectionDialog
at oracle.jbo.jbotester.app.ErrorHandler.displayError(ErrorHandler.java:104)
at oracle.jbo.jbotester.app.ErrorHandler.displayError(ErrorHandler.java:90)
at oracle.jbo.jbotester.app.IErrorHandlerImpl.displayError(IErrorHandlerImpl.java:43)
at oracle.jbo.jbotester.MainFrame.launchConnectDialog(MainFrame.java:409)
at oracle.jbo.jbotester.MainFrame.init(MainFrame.java:577)
at oracle.jbo.jbotester.MainFrame.main(MainFrame.java:538)
Caused by: java.lang.ClassNotFoundException: oracle.jbo.jbotester.jdevx.ConnectionDialog
at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:340)
at oracle.jbo.jbotester.MainFrame.launchConnectDialog(MainFrame.java:407)
... 2 more

After a lot of googling that did no help, I decided to switch JDK from version 1.8 back to version 1.7 to try my luck. It worked! Here's how to do that.

I installed another JDK, which is Java SE 7u67, the latest 1.7 version at the time of this post. After the installation, I have two JDK versions as the following:

$ /usr/libexec/java_home -V
Matching Java Virtual Machines (2):
    1.8.0_20, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_20.jdk/Contents/Home
    1.7.0_67, x86_64: "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home

In Mavericks, it's not easy to switch between multiple versions of JDK. I didn't want to touch the existing JDK 1.8 default to the OS. So, I changed the JDK location for JDeveloper 12c as described at "3.1.1.3 Changing the JDK Location in Linux, UNIX, and Mac OS X" (http://docs.oracle.com/middleware/1213/jdev/install/post_install.htm#CHDFHDCD):

In product.conf, add the following line:

SetJavaHome /Library/Java/JavaVirtualMachines/jdk1.7.0_67.jdk/Contents/Home

Restart JDeveloper, run the ADF Model Tester against the application module,  the problem is simply gone.