JDeveloper 11g together with Oracle ADF provides fully functional LOV component, in 11g you can define LOV in Model, for specific attribute in View Object (ADF BC). However, at the moment there is problem with non-model LOV, main problem - Search region for non-model based LOV not available. For example, you can check my previous sample application, developed with JDeveloper 11g TP3 - List-Of-Values Component in Search and Edit Form. In this application, I was using non-model LOV, it was based on variable in Page Definition. However, same type LOV appears differently in JDeveloper 11g TP4 - without Search region, and its not clear if it will have Search region in next release.
So, what I want to say - usually its not recommended to reinvent the weel, but in practice every developer should know how to implement similar component functionality manually. With Oracle ADF you can implement your own LOV, but if you can wait for new release, or not facing problems with standard component, may be there is no need to implement own...
You can download my sample application - CustomLOV.zip. This application demonstrates how to implement own LOV functionality. Next step will be to implement custom ADF reusable component for LOV. Similar as Glasspane ADF reusable component - Glasspane in ADF Faces RC.
Now I will describe main steps, you can follow if there will be a need to have custom LOV type functionality.
First, we need somehow to open dialog window, it can be done relatively straightforward - to put af:clientListener operation on selected af:inputText field and specify dbClick type for this action. This will allow to raise popup with LOV when dbClick event will be catched.
Popup with our custom LOV is opened using Javascript function.
LOV is based on two sections - Search parameters and table with Results:
Main trick in this application is applied for row selection from LOV. Its not a problem to select row and return it by pressing OK button. But, its little bit more complex to return selected row just by double clicking on any row. Its a problem, because selection event is fired on single selection click, but not on on double click. However, you shouldn't forget - we are using ADF, almost all problems can be solved here ;) So, what i did - I have set af:clientListener with dbClick type for Results table and additionally have set af:serverListener for the same Results table.
Idea - when user performs double click event, Javascript client listener function is invoked and this Javascript function invokes Java method declared in af:serverListener. This Java method basically will retrieve current row from Results table iterator - thats all.
Here are two Javascript functions from developed sample application:
First function is responsible for popup with LOV invocation, second reacts to dbClick event in Results table.
Java code in Backing bean is concentrated into three main methods:
First method works as Dialog Listener, this means is invoked when LOV is closed using OK button. Second method is invoked from Javascript client listener function, when dbClick event is catched in LOV Results table. Third function just retrieving value selected in LOV and assigning it to parent field.
In sample application, LOV is defined for LocationId field, just double click on this field:
Our custom LOV is opened with Search region and Results table:
You see, LOV looks like standard Oracle one, however may be even better - possible to control Results table size :) And finally, when row in Results table is double clicked, selected data is returned to parent component:
Saturday, August 30, 2008
Sunday, August 24, 2008
JBO-25058 and JBO-26001 exceptions
In a case if you will get JBO-25058 and JBO-26001 exceptions after running application developed with Oracle ADF in JDeveloper 11g, most probably my post will help you.
Those exceptions can be thrown, after refactoring Model part implemented with ADF BC. If Business Components Project file with extension *.jpx is moved to different package, jbo.project property available in bc4j.xcfg file must be changed accordingly. However, it is not changed always automatically. If its not changed, two exceptions will appear at runtime:
1) oracle.security.jazn.JAZNRuntimeException: JBO-25058: Definition JobTitle of type Attribute not found in JobTitle
2) oracle.jbo.NoXMLFileException: JBO-26001: XML File not found for the Container /Model.jpx
In order to solve this issue, double check bc4j.xcfg, ADF BC configuration file. For example, if Model.jpx file (this file can have different name in your project) is in lt.andrejusb.model package, jbo.project property in bc4j.xcfg file must be equal to jbo.project="lt.andrejusb.model.Model".
Those exceptions can be thrown, after refactoring Model part implemented with ADF BC. If Business Components Project file with extension *.jpx is moved to different package, jbo.project property available in bc4j.xcfg file must be changed accordingly. However, it is not changed always automatically. If its not changed, two exceptions will appear at runtime:
1) oracle.security.jazn.JAZNRuntimeException: JBO-25058: Definition JobTitle of type Attribute not found in JobTitle
2) oracle.jbo.NoXMLFileException: JBO-26001: XML File not found for the Container /Model.jpx
In order to solve this issue, double check bc4j.xcfg, ADF BC configuration file. For example, if Model.jpx file (this file can have different name in your project) is in lt.andrejusb.model package, jbo.project property in bc4j.xcfg file must be equal to jbo.project="lt.andrejusb.model.Model".
Sunday, August 17, 2008
Show Buttons based on Disclosed Tab
In 11g it becomes quite common use case to structure application page with tabbed panels. If you develop your pages based on templates, most probably there will be separate area for buttons implemented with af:toolbar tag. And this area will not be included into tabbed panel, since template usually will not contain panel elements. Here is example of such structure:
You will face a problem with this structure, when there will be requirement to display different sets of buttons based on different tab (in Oracle ADF, currently opened tab is called - disclosed). This means, area with buttons should be updated, each time user changes current tab.
You can download sample application, where described case is implemented - TabsButtonsDynamic.zip. This sample contains three tabs - Countries, Jobs and Departments. Based on tab currently selected, different buttons are rendered. However, all buttons are initially created on the page, just rendered conditionally.
There are three steps, in order to have buttons conditionally rendered based on currently disclosed tab:
1. Disclosure Listener
Since there is no AutoSubmit property for Tab component, we will use DisclosureListener in order to catch event, when current tab is disclosed:
In this case, we can use the same DisclosureListener for all Tabs.
2. Partial Target
Generated DisclosureListener method will contain only one line of code - it will refresh af:toolbar area with buttons.
As you have noticed, there is no need to refresh each button individually, its enough to apply partial target to toolbar.
3. Rendered property
Each button should have conditional Rendered property.
This property will return boolean value based on currently disclosed tab.
Thats all, really simple and straightforward solution.
If you will run developed sample application, you will notice 4 buttons displayed while in Countries tab - First, Previous, Next and Last:
There will be 2 buttons in Jobs tab - Create and Save:
Finally, 1 button in Departments tab - Save:
You will face a problem with this structure, when there will be requirement to display different sets of buttons based on different tab (in Oracle ADF, currently opened tab is called - disclosed). This means, area with buttons should be updated, each time user changes current tab.
You can download sample application, where described case is implemented - TabsButtonsDynamic.zip. This sample contains three tabs - Countries, Jobs and Departments. Based on tab currently selected, different buttons are rendered. However, all buttons are initially created on the page, just rendered conditionally.
There are three steps, in order to have buttons conditionally rendered based on currently disclosed tab:
1. Disclosure Listener
Since there is no AutoSubmit property for Tab component, we will use DisclosureListener in order to catch event, when current tab is disclosed:
In this case, we can use the same DisclosureListener for all Tabs.
2. Partial Target
Generated DisclosureListener method will contain only one line of code - it will refresh af:toolbar area with buttons.
As you have noticed, there is no need to refresh each button individually, its enough to apply partial target to toolbar.
3. Rendered property
Each button should have conditional Rendered property.
This property will return boolean value based on currently disclosed tab.
Thats all, really simple and straightforward solution.
If you will run developed sample application, you will notice 4 buttons displayed while in Countries tab - First, Previous, Next and Last:
There will be 2 buttons in Jobs tab - Create and Save:
Finally, 1 button in Departments tab - Save:
Friday, August 15, 2008
Oracle ACE Office Hours in the OTN Lounge
Today I got email from Oracle people about Oracle ACE "Office Hours" activity in the OTN Lounge during Oracle OpenWorld 2008.
Main idea of those "Office Hours" is to create opportunity for Oracle ACE's and Oracle ACE Directors to meet with conference participants and to answer possible questions.
I will be on duty after lunch on Monday, September 22 and will be happy to discuss daily things related to JDeveloper/ADF development, and not only...
See you there !
Main idea of those "Office Hours" is to create opportunity for Oracle ACE's and Oracle ACE Directors to meet with conference participants and to answer possible questions.
I will be on duty after lunch on Monday, September 22 and will be happy to discuss daily things related to JDeveloper/ADF development, and not only...
See you there !
Tuesday, August 12, 2008
JDeveloper 11g on Mac OS X Leopard
I'm using Apple Mac Book Pro for about half of a year, but shame for me all this time I was running Windows OS using Apple Boot Camp solution. This product allows to install and run Windows OS on Apple computer exactly the same as on usual PC.
However, I decided to switch to Mac OS X Leopard and to do my work under this OS. I'm glad for this decision, looks like Mac OS is increasing my productivity through user-friendly and helpful interface environment :)
For my usual work I need Oracle XE database, Oracle SQL Developer and Oracle JDeveloper. Its only one little problem with Oracle XE, since this database is not supported in Mac OS. But, it is supported in Ubuntu Linux, so I installed Ubuntu as Virtual Machine (using VMware Fusion) and configured Oracle XE in this OS:
I have installed Oracle XE on Ubuntu using help from this tutorial - Installing Oracle XE on Debian, Ubuntu, and Kubuntu.
In order to use Oracle XE service from Mac OS, I just need to access database using IP assigned for Ubuntu VM by VMware Fusion:
JDeveloper 11g can be launched directly in Mac OS. Before running JDeveloper, I have downloaded and installed JVM from SUN. In order to run JDeveloper under Mac OS its enough to double-click jdev script file available in JDEV_HOME/jdev/bin directory:
For example, ADF BC wizard with applied Mac OS theme looks like this:
If you dont like it, its possible to use default JDeveloper theme even in Mac OS:
This image shows how JDeveloper looks with Mac OS theme:
And finally, application developed with JDeveloper 11g is running in Mozilla Firefox 3.0:
However, I decided to switch to Mac OS X Leopard and to do my work under this OS. I'm glad for this decision, looks like Mac OS is increasing my productivity through user-friendly and helpful interface environment :)
For my usual work I need Oracle XE database, Oracle SQL Developer and Oracle JDeveloper. Its only one little problem with Oracle XE, since this database is not supported in Mac OS. But, it is supported in Ubuntu Linux, so I installed Ubuntu as Virtual Machine (using VMware Fusion) and configured Oracle XE in this OS:
I have installed Oracle XE on Ubuntu using help from this tutorial - Installing Oracle XE on Debian, Ubuntu, and Kubuntu.
In order to use Oracle XE service from Mac OS, I just need to access database using IP assigned for Ubuntu VM by VMware Fusion:
JDeveloper 11g can be launched directly in Mac OS. Before running JDeveloper, I have downloaded and installed JVM from SUN. In order to run JDeveloper under Mac OS its enough to double-click jdev script file available in JDEV_HOME/jdev/bin directory:
For example, ADF BC wizard with applied Mac OS theme looks like this:
If you dont like it, its possible to use default JDeveloper theme even in Mac OS:
This image shows how JDeveloper looks with Mac OS theme:
And finally, application developed with JDeveloper 11g is running in Mozilla Firefox 3.0:
Thursday, August 7, 2008
Glasspane in ADF Faces RC
You can build very cool systems, based on excellent architecture design, with ADF BC or EJB in Model layer and with ADF Task Flows in View Controller layer. However, when it comes time for functional test, tester can break all things only with one question - why when I pressed Apply button and at the same time have pressed couple of other buttons, I got some unexpected result? Well, you probably will answer - you need to wait after Apply button is pressed some minute until operation will be finished and only after it will be done you can press other buttons. I'm sure, tester will not be satisfied with such answer, and application will not be accepted. However, things are not so bad as you can imagine, Frank Nimphius have described how to block page screen during long operation - How-to build a reusable Glasspane in ADF Faces RC. Please read Frank's article, before reading my post, since current post is completely based on it. Here I will describe with sample application how to refresh the screen to show the visual results of the long running operation.
Developed sample application - GlassPaneTest.zip is based on HR schema from Oracle XE database and implements one JSPX page with search form and results table. When you will open this application in JDeveloper 11g, be sure GlassPane reusable component (JAR file) is in correct path. You can check this in JSP Tag Libraries section by opening Project Properties for ViewController:
In this application I'm running two 'long' operations:
Here is the code from Backing bean, where Glasspane is launched and closed:
There are 3 additions comparing to original Frank Nimphius article:
When I'm running this application and doing Search operation, Glasspane appears and not allows to do any changes until operation is not finished:
After operation is finished and result is returned, Glasspane disappears and user can continue his/her work:
Same applies for Save button, during Commit operation screen is blocked and user can relax until operation will be done and Glasspane will disappear :)
Additionally, in ADF Faces RC its possible to use Blocking=True property for buttons. However in most cases its not useful, since user still can do changes on the screen.
Useful Update:
While integrating Glass Pane solution into our project, JDeveloper/ADF developer have found nice improvement. Instead of using refreshCurrentPage() method you can set PartialTriggers property for af:form tag and indicate dependency with Glass Pane popup (for example, in my sample application it will be - af:form partialtriggers="gp:busyPopup"). With this setting, page content is refreshed after popup is closed, without rerendering full page.
Developed sample application - GlassPaneTest.zip is based on HR schema from Oracle XE database and implements one JSPX page with search form and results table. When you will open this application in JDeveloper 11g, be sure GlassPane reusable component (JAR file) is in correct path. You can check this in JSP Tag Libraries section by opening Project Properties for ViewController:
In this application I'm running two 'long' operations:
- filterEmployees(String firstName, String lastName) custom method from Application Module implementation class
- Simple Commit action
Here is the code from Backing bean, where Glasspane is launched and closed:
There are 3 additions comparing to original Frank Nimphius article:
- In onAction(ActionEvent actionEvent) method, I'm storing Id of button component that currently activates Glasspane. I'm doing this, in order to know what logic should I invoke in queryToLaunch(ClientEvent evt) method.
- When Glasspane component is activated, it calls back queryToLaunch(ClientEvent evt) method. In this method I'm accessing stored variable with currently pressed button Id and invoking appropriate functionality.
- In order to present visual changes when operation is finished, I'm calling refreshCurrentPage() method that is doing refresh of the current page:
When I'm running this application and doing Search operation, Glasspane appears and not allows to do any changes until operation is not finished:
After operation is finished and result is returned, Glasspane disappears and user can continue his/her work:
Same applies for Save button, during Commit operation screen is blocked and user can relax until operation will be done and Glasspane will disappear :)
Additionally, in ADF Faces RC its possible to use Blocking=True property for buttons. However in most cases its not useful, since user still can do changes on the screen.
Useful Update:
While integrating Glass Pane solution into our project, JDeveloper/ADF developer have found nice improvement. Instead of using refreshCurrentPage() method you can set PartialTriggers property for af:form tag and indicate dependency with Glass Pane popup (for example, in my sample application it will be - af:form partialtriggers="gp:busyPopup"). With this setting, page content is refreshed after popup is closed, without rerendering full page.
Wednesday, August 6, 2008
ADF Methodology For The Masses on OOW'08
Good news for all JDeveloper/ADF developers - ADF development methodology is in the process, Oracle community is defining it and it'll be available soon. You can track our progress on Oracle Wiki page - ADF Methodology. I believe this methodology will help a lot in daily life, since it will be good reference with descriptions how things should be done in JDeveloper/ADF.
I know its always fun to develop prototypes, but when you in real project, usually you need to have some standard about how to structure application packages, how to define names for components in Model and ViewController layers, and how to find meaningful names for navigation links in application Task Flow. Other important area - reusability. Developers always should reuse code, however how its to do better in ADF, will be described in ADF Methodology. Everyone is free to suggest topics for ADF Methodology, just visit our page on Oracle Wiki.
If you will be on OOW'08, you can register here and attend workshop dedicated to ADF Methodology. Also, you can see how work is progressing on Google Groups - here.
I hope ADF Methodology For The Masses will be same cool as songs from Depeche Mode album - Music For The Masses :-)
See you there in San Francisco !
I know its always fun to develop prototypes, but when you in real project, usually you need to have some standard about how to structure application packages, how to define names for components in Model and ViewController layers, and how to find meaningful names for navigation links in application Task Flow. Other important area - reusability. Developers always should reuse code, however how its to do better in ADF, will be described in ADF Methodology. Everyone is free to suggest topics for ADF Methodology, just visit our page on Oracle Wiki.
If you will be on OOW'08, you can register here and attend workshop dedicated to ADF Methodology. Also, you can see how work is progressing on Google Groups - here.
I hope ADF Methodology For The Masses will be same cool as songs from Depeche Mode album - Music For The Masses :-)
See you there in San Francisco !
Sunday, August 3, 2008
My Session at Oracle Open World 2008 (Oracle Develop)
I was posting some time ago, Oracle selected my abstract to be presented on OOW'08 in San Francisco - Oracle Open World 2008 - Abstract Accepted.
Here is my session details:
Session ID: S300476
Session Title: Oracle Maps in Oracle JDeveloper 11g: A Perfect Combination
Track: Oracle Develop: Java
Date/Time: Monday 09/22/2008 13:00 - 14:00
Venue/Room: Marriott Salon 03
Here is the sample screen of application I will explain during my session:
See you there, in San Francisco !
Here is my session details:
Session ID: S300476
Session Title: Oracle Maps in Oracle JDeveloper 11g: A Perfect Combination
Track: Oracle Develop: Java
Date/Time: Monday 09/22/2008 13:00 - 14:00
Venue/Room: Marriott Salon 03
Here is the sample screen of application I will explain during my session:
See you there, in San Francisco !
Saturday, August 2, 2008
LOV in Find Mode - Workaround for JDeveloper 11g TP4
During this week I have faced an issue with LOV functionality when form is switched to Find mode. I got reply from Oracle, this issue is a bug in JDeveloper 11g. However, for those who need to use LOV components in Find mode in your current project, I will provide temporary workaround. Temporary, I hope until next JDeveloper 11g build.
You can download sample application, where LOV in Find mode works with applied workaround - LOVFindMode.zip. Developed sample contains one form with LOV component.
Its possible to switch this form to Find mode by pressing Find button.
Before describing workaround, I want to remind you about one trick I have noticed with LOV read-only View objects. When you generate Model layer using ADF Business Components From Tables wizard, KeyAttributes property for read-only LOV View objects is not set for some reason. As a result, after value in LOV popup is selected:
Nothing is returned back:
In order to fix this, open your read-only View object you are using for LOV:
And specify key attributes, you can do this directly in XML or through wizard:
Ok, now let's back to main topic of this post - workaround for LOV when form is in Find mode. At first, you can ask - where is the problem? Its easy to answer - select value from LOV popup for first time:
Press LOV icon second time, in order to change selected value - oracle.jbo.SQLStmtException: JBO-27122 is thrown:
For some reason, ADF constructs SQL statement with :vc_temp_1 bind variable, and this variable is not initialized:
oracle.jbo.SQLStmtException: JBO-27122: SQL error during statement preparation. Statement: SELECT Employees.EMPLOYEE_ID, Employees.FIRST_NAME, Employees.LAST_NAME, Employees.EMAIL, Employees.PHONE_NUMBER, Employees.HIRE_DATE, Employees.JOB_ID, Employees.SALARY, Employees.COMMISSION_PCT, Employees.MANAGER_ID, Employees.DEPARTMENT_ID FROM EMPLOYEES Employees WHERE (( (Employees.JOB_ID LIKE :vc_temp_1 ) ) AND Employees.EMPLOYEE_ID = :1)
java.sql.SQLException: Missing IN or OUT parameter at index:: 1
Its Oracle bug, and they will fix it next build, but for those who need to use LOV in Find mode with TP4, may be my workaround will be helpful.
While researching this problem, I have noticed that value from LOV is returned still correctly, even after exception is thrown. So, workaround is simple - just to hide generated exception. In 11g you can use centralized custom error handler class where reported exceptions can be managed.
This class should extend from DCErrorHandlerImpl class and should be registered in DataBindings.cpx file:
I'm catching generated exception in overrided reportException method and not reporting it, all other exceptions are reported as normal:
When this workaround is applied, you can open LOV popup when form is in Find mode as many times as you want - no error popup, and value from LOV is returned:
If you will check your server log, you will find entry that indicates information about catched but not reported exception:
You can download sample application, where LOV in Find mode works with applied workaround - LOVFindMode.zip. Developed sample contains one form with LOV component.
Its possible to switch this form to Find mode by pressing Find button.
Before describing workaround, I want to remind you about one trick I have noticed with LOV read-only View objects. When you generate Model layer using ADF Business Components From Tables wizard, KeyAttributes property for read-only LOV View objects is not set for some reason. As a result, after value in LOV popup is selected:
Nothing is returned back:
In order to fix this, open your read-only View object you are using for LOV:
And specify key attributes, you can do this directly in XML or through wizard:
Ok, now let's back to main topic of this post - workaround for LOV when form is in Find mode. At first, you can ask - where is the problem? Its easy to answer - select value from LOV popup for first time:
Press LOV icon second time, in order to change selected value - oracle.jbo.SQLStmtException: JBO-27122 is thrown:
For some reason, ADF constructs SQL statement with :vc_temp_1 bind variable, and this variable is not initialized:
oracle.jbo.SQLStmtException: JBO-27122: SQL error during statement preparation. Statement: SELECT Employees.EMPLOYEE_ID, Employees.FIRST_NAME, Employees.LAST_NAME, Employees.EMAIL, Employees.PHONE_NUMBER, Employees.HIRE_DATE, Employees.JOB_ID, Employees.SALARY, Employees.COMMISSION_PCT, Employees.MANAGER_ID, Employees.DEPARTMENT_ID FROM EMPLOYEES Employees WHERE (( (Employees.JOB_ID LIKE :vc_temp_1 ) ) AND Employees.EMPLOYEE_ID = :1)
java.sql.SQLException: Missing IN or OUT parameter at index:: 1
Its Oracle bug, and they will fix it next build, but for those who need to use LOV in Find mode with TP4, may be my workaround will be helpful.
While researching this problem, I have noticed that value from LOV is returned still correctly, even after exception is thrown. So, workaround is simple - just to hide generated exception. In 11g you can use centralized custom error handler class where reported exceptions can be managed.
This class should extend from DCErrorHandlerImpl class and should be registered in DataBindings.cpx file:
I'm catching generated exception in overrided reportException method and not reporting it, all other exceptions are reported as normal:
When this workaround is applied, you can open LOV popup when form is in Find mode as many times as you want - no error popup, and value from LOV is returned:
If you will check your server log, you will find entry that indicates information about catched but not reported exception: