Thursday, March 18, 2010

Using transient attributes to improve the usability of Query Panel

A simple demo application that uses transient attributes to format(re-arrange) fields displayed in model driven query component is attached here
In this sample application, query panel displays an 'Employment Date' field (which is a transient attribute) and the value keyed in for this field is mapped to a bind variable. This bind variable can be used by the Criteria Items to form the required 'where clause', based on the use case requirement. Please note that, 'display property' of Criteria Item can be controlled from the UI Hints tab (UI Hints tab -> Rendered Mode-> All/Basic/Advance/Never). In the attached sample application, first two criteria items are not displayed to the user, but the actual query is getting generated basen on these two items only.
 SELECT .... FROM JOB_HISTORY JobHistory WHERE ( ( (JobHistory.START_DATE < :bndVarEmplDate ) AND (JobHistory.END_DATE > :bndVarEmplDate ) ) )

 
ViewCriteria and the resulting Query Panel

[Runs with Oracle JDeveloper 11g R1 PS1 + HR Schema]

Wednesday, March 17, 2010

What you may need to know about Nested Application Module

Nesting of Application Module

Oracle ADF provides a modular application development platform where you can logically group the business services in to 'work units'(AKA ApplicationModule) and compose these individual modules to from a larger system based on use case requirements. This feature of composing/nesting ApplicationModules inside a root ApplicationModule is very useful when you build huge enterprise solutions. To learn more about this, please read section 9.4 Defining Nested Application Modulesfrom Fusion Developer's Guide. This blog article talks about a specific use case scenario where a page consumes services exposed from multiple ApplicationModules and examines how the nesting of ApplicationModule eliminates some weird errors and improves system performance

A case study

Let me share an interesting use case scenario related to this topic. In this case, a specific flow was using complex stored procedures to update database tables, and another alternate flow was using EntityObjects to update the same sets of tables. Database Stored procedure was containing some complex business logic to update multiple records across tables. When user clicks on 'Save' button on the screen, this action invokes ApplicationModule's custom method and this in turn calls stored procedure to update tables. If all goes well, AplicationModule commits transaction as last step.
All goes well so far… The real fun starts when a different user transaction tries to update Entities based on those Database Tables which got updated as part of previous transaction (through stored procedure). Unfortunately, the second transaction fails with the below error while committing the changes back to database.

oracle.jbo.RowInconsistentException: JBO-25014: Another user has changed the row with primary key oracle.jbo.Key[SB0000000000231 BC00000013 BA0028 ].
at oracle.jbo.server.OracleSQLBuilderImpl.doEntitySelectForAltKey(OracleSQLBuilderImpl.java:1062)
at oracle.jbo.server.BaseSQLBuilderImpl.doEntitySelect(BaseSQLBuilderImpl.java:548)
at oracle.jbo.server.EntityImpl.doSelect(EntityImpl.java:7762)
at oracle.jbo.server.EntityImpl.populate(EntityImpl.java:6486)
at oracle.jbo.server.EntityImpl.merge(EntityImpl.java:6823)

Google search for this error presented two promising links. These two great posts actually speak in detail about this error and provide some possible solutions as well.

Why Do I Get oracle.jbo.RowInconsistentException?
Bring Back the Hobgoblin: Dealing with RowInconsistentException

Unfortunately, none of the suggestions from these two posts really helped to solve the issue described in the above case.

So what goes wrong here?

The above mentioned use case is making use of both Stored procedures and EntityObjects to update same set of database tables, in different use case scenarios. As you know, ADF BC layer is keeping working copies of entity rows in cache when you retrieve data using ViewObject . While you commit a transaction, Transaction Manager actually scans each entity cache and call commit on dirty entities. If you use stored procedure for committing changes back to database, actually you are by passing built in synchronization mechanism provided by ADFBC to synchronize changes between EntityObjects and Database tables. As the rest of the article is based on this specific scenario, let me try to make it clearer. When we use stored procedure to update database tables, the data modification actually happens outside of ADF BC context. Apparently, EntitytObject in the cache are not aware of this changes and they still hold the stale data. So next time, from a different flow, when you try to commit data using this 'stale' EntityObject, system will go and check whether Entity state is in synch with database table and if it find any mismatch then throws oracle.jbo.RowInconsistentException.
On a related note, please go through Section 40.10.11, How to Protect Against Losing Simultaneously Updated Data from developers guide to learn more about the "lost update" detection for EntityObject

Hmm…So what next?

One obvious solution here is to clear the Entity Cache right after committing the transaction (here, Commit on transaction is called after invoking the Stored procedure). You can either do it by setting Transaction::setClearCacheOnCommit(true); or by Transaction::clearEntityCache(entityName)
Theoretically, the above step is enough to resolve the issue. Interestingly, one team reported saying that in a specific case system still throw the same error, even after clearing the cache.


Oops... what goes wrong again?

Further investigation shows that, this weird behavior is purely because of peculiar implementation approach adopted for realizing the use case. Here, two ApplicationModules were created, one for dealing with all stored procedure related functionalities and the other one to deal data retrieval + manipulation using related ViewObjects and EntityObjects. To make thing worse, these two ApplicationModule were not nested, so both these AapplicationModules were working in their own world. Please note that Entity Cache is kept at Transaction level. So clearing EntityObject cache from one ApplicationModule will never have any effect on cache from a different transaction. This answers the above question. In the above case, 'clearing entity cache' was actually clearing cache from the current ApplicationModule. But there were pages using a different ApplicationModule to get data from same tables using ViewObject. So this ApplicationModule's entity cache went out of synch with database records, when the first transaction commits data using stored procedure

Now, we know the root cause for this erroneous behavior. Time to act...
Obviously, easiest solution here is to nest ApplicationModule and generate a composite service layer by nesting/composing required ApplicaionModules. All of the nested ApplicationModule instances share the same transaction and entity object caches as the root application module that reuses an instance of them.  So if we adopt 'ApplicationModule nesting' approach for the above use case, UI page actually deals with single root ApplicationMdoule and  eliminates the above said erroneous scenario.


Why should you consider nesting ApplicationModule wherever possible?

Advantage is that all nested ApplicationModule participate in same transaction, so same DB connection is used while serving a request (A new transaction implies new DB Connection). As a bonus you get more modular, scalable and robust enterprise application matured enough to meet today's challenges :)

PS: Many thanks to Radhika Mukund, who really helped me in writing this blog article!



Learn More ...

There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html

Sunday, March 7, 2010

Layout Tips - Stretching components to fit browser window

ADF Faces is packaged with rich set of layout managers which makes layout problems trivial. If you really want to have a feel of ADF Faces Layout components, please go through this ADF Faces Demo. If you come from Java Swing world, you can see lots of familiar faces here as well. I really like the ADF Faces stretchable layouts with which you can easily build hassle free, browser friendly web applications. Recently, I noticed an interesting post from Matt Cooper on exploring the richness of PanelStretchLayout - Stretchable Tiled Layout . This idea is very useful when you need to stretch multiple child components based on the browser size.

A Case Study

At this time, let me share some basic tips on lay outing components on a web page built using ADF Faces by taking a simple example.

Consider a use case where you need to build a web page as shown below.


Apparently, screen is split in two parts - left hand side contains basic search functionality and right hand side contain a tabbed pane. UI requirement here is that inside the right pane all the components are supposed to occupy maximum available size on the screen(i.e. components are supposed to be stretchable). ADF Faces lay outing mechanism got a PanelSplitters component to divide a region into two parts with a repositionable divider.

PanelSplitters are used to divide a region into two parts with a repositionable divider. The two parts are identified as the "first" facet and the "second" facet. If the contained component supports it, the contents of a section will stretch to fill up all available space in that section. The panel splitter can be adjusted with the mouse, by pressing a collapse button, or by use of the arrow keys when the splitter is selected. A panel splitter can split horizontally or vertically based on the orientation attribute.

So af:panelSplitter can be used to split the screen in the above mentioned case as well.

Tabbed panel on right hand side can be realized using af:panelTabbed

This component uses <af:showdetailitem> to organize content into each tab body panel. The <af:showdetailitem> will allow stretching if:
* It contains a single child
* It has stretchChildren="first" specified
* The child has no width, height, margin, border, and padding
* The child must be capable of being stretched


At this stage, the jspx may look like as shown below;


How to stretch child components?

Now the task left is to identify the layout for the container which is smart enough to stretch it children as well. Fortunately ADF Faces do support af:panelStretchLayout that fits well with our requirement.

The panelStretchLayout component stretches the child in the center facet to fill all of available space. The available space may be constrained by the presence of other children in the top/bottom/start/end facets. When these children are present, they occupy space defined by the topHeight/bottomHeight and startWidth/endWidth attributes.

So far, so good. Now’s the time to sweat your brain. <af:panelStretchLayout>  comes with only 3 facets. As per the above UI design requirement, it is required to have 4 graphs to be displayed in equal size, occupying the available area on the parent container. No worries, <af:panelStretchLayout>  is smart enough to stretch it child 'layout containers' as well and there is a provision to specify heights in percentage for each facets ( topHeight / bottomHeight). So let us go ahead and add a child panelStretchLayout to keep the additional elements. Now the web page may have the below shown structure.


How to stretch a table?

Before winding up this session, let us have a quick look at stretchable table as well. Consider the second tab of the above UI where the requirement is to stretch table to fill the entire available area.


Obviously table (Here table is added inside panel header) needs to be wrapped inside a af:panelStretchLayout. Interestingly af:table got one special attribute - columnStretching - for stretching one of its column to spread over the available space of its immediate parent container. And ideal column for stretching could be one with maximum length, say for example 'description' column.

Further Reading
Chapter 8 Organizing Content on Web Pages from Web User Interface Developer's Guide will help you to understand ADF Faces layout components better.
Learn More ...

If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html