Friday, November 27, 2009

Creating a Data Capture Form using EJB + JPA and ADF Binding

Java EE technology stack has been improved tremendously in recent past. However, a closer look at this technology spectrum reveals the visible gap that exists between the UI and Service layers. Core Java EE stack really lacks a smart glue layer that avoids large chunk of boiler plate code used for wiring UI with business data. For a typical Java EE business application, we can say that about 20-25% coding effort is being spent for wiring UI to the data from business services and other common UI manipulations such as synchronizing master-child relations, querying entities and displaying results, navigating between records, invoking actions etc.

Binding the UI with EJB

Is there any matured binding solution available for Java EE technology stack?
Answer is YES, Your friend is ADF binding layer who can really help you to bridge the gap between UI and business service layer.

Seeing is Believing

So let us try building a data capture form using Java EE technology stack with the help of JDeveloper + ADF Binding Layer , and see how this toolset saves you time and effort.

Let us take the classic example of Employee and Department. The use case is to realize a data capture screen for an Employee. UI may look like as shown below



The example below illustrates how JDeveloper help you to build Java EE applications quickly and efficiently.

Setup the application environment

Step 1: Create a new application by choosing Java EE Web Application template.



Please make sure that required libraries are selected in subsequent steps of the same wizard. Click Next and finish the wizard. This wizard automates the 'setup' of the basic application structure (I would say, architecture rather) for you with clear separation between UI and Service Layer. You can see two projects generated at this stage 1. ViewController (UI) 2. Model (Business Services)







Step 2: Create a new Database Connection. This example uses HR schema that comes with Oracle database



Generate entities from tables

Step 3: Select the Model project, right click, and select New from the context menu. From the dialog, select the option for generating 'Entities from Table'. Select DEPARTMENTS and EMPLOYEES tables in the next step and continue the wizard with default values. Click to Finish at the end. Wizard generates Employees and Departments entities and the required configuration files as well, like persistence.xml file.





Define entity validation declaratively

Step 4: ADF Binding layer provides declarative validations support for the enterprise applications. Binding layer also supports, UI hints for entity attributes which can be later leveraged by the view layer to derive the runtime characteristic of UI elements.

Let us define the validation for email of an Employees entity. Open the Employees.xml in design mode, choose attributes tab and select employee attribute. You can see validators section displayed at bottom. Click on the + icon to add validation. Select ‘Regular Expression’ as Rule type. From the 'expression' drop down list, select Email Address. Now go to the failure handling tab and key in the error message.



Define UI Hints

Step 5: UI Hints defines hints for the attribute which can be later used by the view layer to derive the UI characteristics like filed label, length, precision, required flag etc. Select the entity attributes and specify values for Label, Tooltip, Display width, Precision etc using Property Inspector



Generate service layer (session facade)

Step 6: We done with the model part.  Let us go ahead and generate service layer for the model. Select the persistence.xml file (displayed under META-INF folder of Model project), right click and select the option to create Session Facade. Continue the wizard with default options till the end. This generates SessionEJBBean and other supporting files(Local and Remote interfaces and related configurations). SessionEJBBean will contain the basic infrastructural service methods (generated by the wizard, off the shelf) for performing CRUD operations on the containing entities.



Create accessor method for entity

Step 7: This accessor method will be used later, to retrieve the instance of the entity from the client .
Open the SessionEJBBean, write down the method public Employees getEmployees() as shown in the below diagram. Copy the method declaration to Local and Remote interfaces(SessionEJB.java and SessionEJBLocal.java).This method provides the Employees entity instance that backs up the data capture form.


Generate Data Control

Step 8:  Select SessionEJBBean, right click and select Create Data Control option from the menu



Create UI for the application

Step 9: Create a jspx page. Drag and drop the employees method accessor from the Data Control pallet to the jspx file as a Form. Now the form is ready, let us replace the departmentId field with a SelectOneChoice component, see next step.



Step 10: Define List binding for department. Objective is to support the department filed with a SelectOneChoice component. Create List binding by selecting departmentsFindAll method accessor.






pagedefinition entry :

<list ListOperMode="navigation" 
     IterBinding="departmentsFindAllIterator"
     ListIter="departmentsFindAllIterator" id="departmentLOV"></list>
Step 11: Make changes in jspx file to add a <af:selectOneChoice> for department, as shown below.

 <af:selectOneChoice value="#{bindings.departmentId.inputValue}"
          label="#{bindings.departmentId.hints.label}"
          required="#{bindings.departmentId.hints.mandatory}"
          showRequired="#{bindings.departmentId.hints.mandatory}"
          shortDesc="#{bindings.departmentId.hints.label}}"
          id="soc1" valuePassThru="true">
       <af:forEach items="#{bindings.departmentLOV.iteratorBinding.allRowsInRange}"
                    var="li1">
          <af:selectItem id="si2"
                 label="#{li1.dataProvider.departmentName}"
                 value="#{li1.dataProvider.departmentId}"/>
       </af:forEach>
  </af:selectOneChoice>

Persist Enity

Step 12: Drag persistEmployees(Employees employees) method action as command button on the Form. Specify the parameter value as #{bindings.employeesIterator.currentRow.dataProvider}






That’s it, job is done without much effort. Now you can try running the page from JDeveloper. Sample workspace is attached below.

A couple of points:
1. Please note that accessorIterator for the employees needs to be refreshed during each page load. So  added a PageController ,to rexecute the IteratorBinding when page loads.
2. Modified the generated source of SessionEJBBean::persistEmployees(Employees employees) to get the reference of associated Departments.

You can download the sample workspace from here.

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

14 comments:

Kavin Kumar said...

Thanks Jobinesh. Really well explained. Explains the real power of ADF Binding layer for a Fusion apps developer like me who is more used to ADF Model too :-)

Yes, Its me, Kavin from Financials.

Does ADF Binding layer offer any specific performance benefit than the traditional approach for such use case.

Jobinesh said...

Hi Kavin
Good to see you here :)

As you know, ADF Binding Layer binds UI to business service in a seamless way. So the focus is mainly to
1. Avoid the boilerplate code,
2. Decouple UI from the underlying server technology and
3. Improve developer productivity. That said, however binding layer is smart enough to cache the 'iterator' data between page navigations and postbacks(this can be turned off if needed), so as a bonus you can leverage certain performance improvement.

Kavin Kumar said...

Jobinesh, Thanks for explanation.

I was was mainly concerned on the performance side and "CACHING" is really a very good one compared to the traditional way of implementing this.

I will recommend to some of my friends who are using EJB :-)

Anonymous said...

Jobinesh,

When talking about the "avoiding the boilder code" what exactly do you mean?

I have worked with BC4J since 1999 and let me tell you this is not BC4J strong point. You end up with lots of other "cpx" files that sometimes you need to modify because JDeveloper IDE does not sync them properly on large projects.

Your second point of decoupling the UI from server technology is missing the point. JSF does it and not BC4J. You are talking about BC4J right? This is the persistence layer.

Oracle has run out of options I think. It has an issue with standards like JPA. Today (2009) developers and enterprise prefers JPA and new JSF 2.0. And by the way I think the new JSF spec and JPA/EJB puts a nail into Oracle proprietary technology like BC4J.

It was good in 1999 not today.
My last point is of the performance between BC4J and JPA or even TopLink. In large deployments (and I have done few) JPA and TopLink outperforms BC4J and at the end you (developer) end up with much better architecture for your applications OO vs. "I do not what!".

I hope you reconsider developing real applications with JPA and NOT BC4J.

mark

Jobinesh said...

Mark,

The whole objective of this post was to highlight the benefits of using ADF binding layer (JSR 227) when you develop JavaEE based applications. Let me share my experience using J2EE(JavaEE) tech stack. Agreed that JavaEE stack has been improved in recent past. But I believe that, there is still room for improvement and the gap between UI layer and business service is still on higher end. If you take any of the applications built using Core Java EE, you might notice lots of repetitive code done to bind UI(JSF) with Business services(EJB/webservices). Generally speaking, these repetitive codes do the following
* Error Reporting (Entity level/Attribute level)
* Pagination
* query/search form functionality
* Security and related mechanisms
* Seamless invocation of business services etc.

By the term 'boilerplate code', I meant the code written to achieve the above tasks. Obviously, the above tasks are of generic nature and each and every application based on JavaEE stak needs to address these items in a custom/proprietary way . ADF provides solution for each of the above mentioned items and binding layer plays a vital role here. Check out this http://jcp.org/en/jsr/detail?id=227
(btw, this blog post is focusing on ADF Binding Layer for EJB, not on BC4J )
Upcoming Java EE 6 release includes some promising enhancements; still the 'Wow' factor is missing.

Anonymous said...

Mark missed the fact that your example used JPA, and not ADF BC (or BC4J as it use to be called).

Before you criticize an example, you should probably try and see what it actually did...

dayo salawu said...

hi Jobinshesh, i'm new to ADF and her controls, porting from jsp's but familiar with ejbs'

with respect to your very helpful posting, i noticed that when the form loads the fields are empty despite the fact that the content loads from the findAll data control and i removed the reset control from your sample application and this didnt stop the behaviour.

can you advise how this this achieved. i have done a sample web form but the content of a row is loaded from the datasource and i do want to keep this as clean as possible that is the data entry forms are reset and ready for input by default. thanks

Jobinesh said...

Hi Dayo
Please see these lines in my post....
"Please note that accessorIterator for the employees needs to be refreshed during each page load. So added a PageController ,to rexecute the IteratorBinding when page loads."

MaxMcByte said...

Hi,

Tried you sample with JDeveloper 11.1.1.40 and received the following error.

<Failure occurred in the execution of deployment request with ID '1302112632204' for task '1'. Error is: 'java.lang.NoSuchFieldError: DETACH'

Any ideas?

Thanks...

Jobinesh said...

You are right MaxMcByte, I'm able to reproduce this error on 11.1.1.4.0. Thanks for pointing it out.
Will update you soon with a solution
thanks

Jobinesh said...

Ooops may bad.One of my entity has been using CascadeType.DETACH which is missing from JPA 1.0,Corrected and uploaded again
http://download.oracle.com/javaee/5/api/javax/persistence/CascadeType.html

CascadeType.DETACH has been added in JPA 2.0 / JEE6.
http://download.oracle.com/javaee/6/api/javax/persistence/CascadeType.html

John said...

It is great. Very helpful

pappu said...

Hi This is sashank ,

very nice post , could you please let me know how did u add the LOV through select one choice as i was not able to replicate and i am new to ADF .

Thank you in advance ,
Sashank P

mohsen bahadorian said...

Hi Jobinesh

What is the role SessionEJBLocal.xml in this post?

What kind of file is that?How I can create it ?Is this file and 2 other Departments.xml and Employees.xml required while we have JPA entities?

Thanks
Mohsen