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.
The Challenge
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.
The Approach
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.
The Result
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.
Follow Up:
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!
Resources
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.
It is certainly true that the primary target of JHeadstart is transactional data-oriented web applications. And yes, in any project of reasonable complexity, you will need postgeneration modifications / extensions to the generated screens. 100% generation is certainly not a goal in itself , although some people like Lucas (and myself) like to stretch the capabilities of the JHeadstart Application Generator as far as possible. Take a look at the jheadstart web log (www.orablogs.com/jheadstart) for other advanced examples like generating wizard-style screens.
With Oracle Consulting, we use JHeadstart through the entire lifecycle of the project. Apart from Design and Build, JHeadstart is a great help during Analysis when you want to apply an iterative/agile approach. Nothing better then showing some working screens a few days after a requirements workshop to validate user requirements!
Using ADF with JHeadstart, Oracle Consulting is able to offer J2E E projects using the same productivity figures as we do for Designer/Forms projects. That would not be feasible if JHeadstart would only help during the first days (or even minutes 🙂 of the project.
Many people associate application generation with increased productivity and decreased flexibility. We believe that one of the strongest benefits of Jheadstart is that is does NOT limit your flexibility. We do not generate any java code that is hard to maintain, just UIX/JSP pages, and a struts-config that is build on a generic, very extendable Struts action class.
The runtime architecture you get is the same, whether you use JHeadstart to generate, or you start with drag and drop from the beginning. Only if you force yourself to stick to 100% generation, you are limiting yourself to what JHeadstart can generate for you.
Jan, you should then use it like this: “JHeadstart speeds up what are the first 35 minutes when using JHeadstart or the first three weeks when not.”
And of course JHeadstart is a productivity booster – surely you gathered that much? And at the same time, the exact benefits depend on the project involved. If you do not build against a database, there are virtually no benefits. If you build a WebService frontend – again no substantial benefits. Data-oriented OLTP style Java/J2EE Web Application: yes, that’s the one. And I know we both have been building quite a few of those.
Well okay then, what are you guys saying? Is ADF/JHeadstart a productivity booster or not, or does it depend on the project involved? @Rob; I really liked your slogan – I’m definitely going to use this one myself if you don’t mind 😉
Nice slogan: “JHeadstart considerably speeds up the first 35 minutes of development!” 😉
Rob van Maris
Jan,
I do not agree with your statement that “If you can generate stuff completely and never ever have to change it afterwards, of course this is faster than manually building the same functionality”. It very much depends on the complexity of both the application that you want to generate and the generator used. For instance, generating a “Hello World” application may very probably be slower than writing it by hand.
Besides that, configuring a generator to generate what you want it to will take a substantial amount of time. In the case of an application generated by JHeadstart on ADF BC components you will need to configure the ADF BC components and then JHeadstart to get generated what you want. If you misconfigure any component in this process, you will have to go back, reconfigure and regenerate.
With a complex technology like ADF (with the sheer number of files involved) generating will most likely beat creating all files by hand. But this doesn’t mean that in other situations, coding by hand may very well beat generation.
Wouter van Reeven
Jan, thanks for your reaction. I am not quite sure though what your point exactly is. If and when JHeadstart would be limited to a very narrow range of UI widgets and application flows, and I would have picked the only one it really excels at, you would be absolutely right. And if JHeadstart would not allow you to extend what is generated in a simple way, you would be even more right.
However, and I take it you are well aware of it, JHeadstart generates a substantial number of different UI controls, different page layout and support many different flows to unlimited nested levels.
Besides, the generated code is completely visible and can be seen as the code manually developed by your colleague who had a productive week while you were away skiiing somewhere. What I am trying to say is that JHeadstart provides enormous functionality in many aspects of data oriented applications and only needs manual complements in some.
I do not need to gear my demo towards JHeadstart in order to get superior productivity. Perhaps it is time for a real RAD race, not a virtual one…
I think this: “And I happen to know this requirement fits JHeadstart very well – it can be generated completely!” says it all. If you can generate stuff completely and never ever have to change it afterwards, of course this is faster than manually building the same functionality. This is true for JHeadstart and for any other generator tool.