In this article I will demonstrate how I implemented a fairly complex requirement from one of my customers in a very real Java/J2EE Web Application. This requirement involved a Master-Detail-Detail construction for the maintenance of Lists with Contacts, using two Multi-Select Lists of Values and a so called Table Detail Disclosure. The technology used for the implementation was: Oracle Database, Oracle ADF Business Components and ADF Binding Framework and ADF UIX, supported by the runtime library from JHeadstart as well as the time design JHeadstart Application Generator. Implementing the application took me all of 35 minutes. I challenge any other technology stack not involving JHeadstart to do it in less than 10 times that long! To be fair, there was not really a RAD race. And I happen to know this requirement fits JHeadstart very well – it can be generated completely! But still, it is not too exotic and I am convinced no other technology stack in the Java/J2EE arena would have come close in terms of development productivity.
So here is the requirement: starting from the following database design, create an application that allows us to maintain Companies, Persons and Lists with entries of either Companies or Persons. When maintaining the entries for a list, we must be able to use a popup List of Values to select multiple Companies or multiple Persons to add to the list in one action.
Note: this is a trimmed down variant of the real requirement that was slightly more complex and embedded within a much larger application. Note also that I have implemented the database beforehand – took me about 15 minutes – as it is not really part of the demonstration I wanted to give of the development of the web-application using the technology described. The database consists of four tables, one sequence and four Before Row Insert triggers that assign values to the primary key column ID using the sequence. You can download the database creation scripts including some sample data below under Resources.
Using JHeadstart 10.1.2.1 and JDeveloper 10.1.2, I started by created a new Application Workspace, Default Web technology template. This creates a Model and a ViewController project. I JHeadstart Enabled the ViewController project from the Right Mouse Button menu on the Project node. I now create Business Components from Tables from the New Gallery from within the Model project. I create a connection that my X database schema that contrains the four tables of my application. I select all four tables and create Entity Objects and default ViewObjects for them. I call the Application Module the ContactListServices. The ADF BC wizard creates View Links for all Foreign Keys – I will make use of these ViewLinks when creating the JHeadstart application.
Next I go in each Entity Object to make the Id attribute not mandatory and check the Refresh After Insert checkbox. This deals with the fact that the value for these attributes is derived from the sequence inside the Insert trigger and therefore ADF BC should not enforce the mandatory-ness of these four attributes.
Now I realize that my ViewObject ListEntriesView is not satisfactory for my web-application: I am going to maintain two separate blocks of Company List Entries and Person List Entries respectively. So I need two new View Objects, very much like the ListEntriesView, called PersonListEntriesView and CompanyListEntriesView.
I also create ViewLinks between these views and the ListsView and with the PersonsView and CompaniesView respectively. Finally I create a new View Object PersonsInCompanyView which is a copy of the PersonsView, but that will be used for displaying all people in a company under the Company List Entries. This last view object PersonsInCompanyView also gets a ViewLink with the CompanyListEntriesView on their CpyId attributes. After updating the Application Module’s data model with the new viewobjects, it looks like this:
Next I turned to the ViewController project and create a new JHeadstart Application Structure file, once again from the RMB menu on the project node. Then I further specify the Groups in my application: one for Companies – a straight Table layout group based on the CompaniesView – and another one almost as straightforward for People, based on the PersonView albeit slightly more complex because of the Lookup on Companies. The piÃ¨ce de rÃ©sistance in this application is the Lists Group. It is a table form layout with two detail groups, one for the Person List Entries and another one for the Company List Entries, both on the Same Page and in Table Layout. The Person List Entries group has a Lookup for multi-selecting Person records to add them all at once to the list as new list entries. The Company List Entries group also has a lookup for a popup List of Values window from which multiple Companies can be selected to add to the list. In addition, the Company List Entries group has a child group with – read only – the Persons in that Company. These are shown on the same page in a Table Detail Disclosure.
After specifying all this in the Application Structure File editor, I generate the application with the JHeadstart Application Generator, which spits out UIX pages, ADF UI Models and a struts-config.xml file as well as some resource bundle entries.
Now it is time to run the application and enjoy the splendour of its functionality. The clock is ticking and we are approximately 28 minutes under way. Generation takes about 40 seconds, starting up the application for the first time a trifle longer. Then we can browse through the application:
First these three ‘simple’ maintenance screens. However, when we follow the Details button from the Lists page, things start to get more interesting:
We see the List Entries of type Company and of type Person. For List Entries of type Company, we see in an in-line table – in the Table Detail Disclosure – the list of Persons in that Company. When we click on the Search Light icon, we open the Multi Select List of Values. For example to select people:
In the List of Values popup window, we can search for persons in our application and subsequently select one or more. When I close the List of Values (window), the selected values are copied back to the PersonListEntries-iterator and -bindings, and for each selected Person, a PersonListEntry record is created.
Here things start to go wrong: after I click on save – to commit my changes to the database by way of the ADF Business Components layer – the page returns with not only my new PersonListEntry records but also an equal number of "phantom" company list entry records, without meaningful values. After forcing a requery on the database, the phantomrecords disappear. As far as I can tell, they are not created in the database, nor are they created in the ADF BC layer – no ViewRowImpl records. They seem only to exist in the ADF Binding Layer, in the iterator bindings. Debugging so far could not explain what happens. However, I know that the phantom records appear immediately after the onLovSelect event has been processed; I have changed the messageLovInput’s partialTargets attribute to include the table id of the CompaniesListEntries table: now the phantom rows show up immediately after the LOV is closed.
After some discussions with Steven I tried to move some stuff around. Eventually I found out that if the ViewObjects on which these two table-blocks are based are built on different Entity Objects, then the application works as desired. So it is not a good idea to have – probably in the same UIModel – multiple Iterators based on ViewObjects that are based on the same EntityObject.
Note: this is only a work-around: I still do not know exactly what goes wrong and why!
You can download the database creation scripts including some sample data here: nawDDL.sql.
The JDeveloper 10.1.2 Application Workspace with the entire application can be downloaded here: MultiSelectLOVDemo.zip(870 Kb)
Note: if you want to regenerate the application, you will have to download and install JHeadstart 10.1.2, which you can find here: http://www.oracle.com/technology/consulting/9iServices/JHeadstart.html.