Tuesday, February 28, 2012

NullPointerException at ScopeIdAnalyzer - Calling PopUp from Declarative Component

Update: This bug is fixed in upcoming JDev release.

If you develop advanced ADF declarative components, I'm sure sooner or later you would face requirement to implement custom reusable popup. Ideally we would like to invoke custom reusable popup directly from button declared in the fragment or page. This works well on runtime, but JDeveloper 11g R2 IDE generates internal NullPointerException at ScopeIdAnalyzer - I will show how to workaround it.

Sample application provides declarative ADF component with basic popup - CustomPopUp:


Once we drag and drop such component into fragment or page, we can reference ADF popup from inside of declarative component by expanding customPopUp and selecting popup ID. This ID can be mapped with showPopUpBehavior tag to display popup on button click:


This works on runtime, by on design time generates IDE error - once you press OK button to confirm popup ID:


In source mode we can see error description - seems like, JDeveloper is not able to resolve popup ID from declarative component dependency (even it is visible from the wizard):


It works on runtime, but is quite annoying to get NullPointer exception each time when working with page/fragment in IDE. Workaround: invoke popup from declarative component programmatically.

Create binding mapping for custom popup declarative component and action listener mapped with opening button:


From action listener, get instance of declarative component binding, get collection of children and retrieve oracle.adf.Popup family component - show popup:


Popup from declarative component is opened programmatically:


Download sample application (JDeveloper 11g R2) - DeclarativePopUpApp.zip.

Saturday, February 25, 2012

WebCenter Portal 11g PS5 Performance Improvements

What's New section from Oracle Fusion Middleware Developer's Guide for Oracle WebCenter Portal 11g Release 1 (11.1.1.6.0) says that there are performance improvements in PS5 release - accelerated performance at design time and runtime. Specifically:
  • Experience faster initial page downloads.
  • Forgo session creation for unauthenticated users.
  • Realize faster creation times for WebCenter Portal: Framework applications.
Besides this information, it would help to have some metrics showing improvement in numbers. When there are no numbers, is hard to say if it was really improved or no. Its why I decided to look into this and post simple comparison numbers with previous WebCenter PS3 release. I will compare against tests with WebCenter 11g PS3 - WebCenter 11g PS3 Performance Tuning and Iterative Development Mode. Download migrated sample application to PS5 - WebCenterPerformance_v2.zip.

Let's look first into WebCenter application deployment time on integrated WebLogic and compare it with plain ADF application deployment time.

Basic ADF application on JDeveloper 11g PS5 is deployed in 14 seconds:


Basic WebCenter application on JDeveloper 11g PS5 is deployed in 40 seconds:


This is 26 seconds difference, it grows exponentially with more complex applications - WebCenter application deployment time is quite slow. There is still room for improvement in deployment time for WebCenter. Also, with more complex WebCenter applications - integrated WebLogic server goes out of memory after 3 redeployments in average (while you can do around 30 - 50 redeployments for ADF application before going out of memory).

Now we move to the next topic - login and authenticated session creation in WebCenter Portal 11g PS5. Login procedure and home page load for basic WebCenter application is completed in average 813 milliseconds, 13 requests and 1.2 MB of data:


If we refer to PS3 timing, same action was completed in average 1.18 second, 17 requests and 1.6 MB of data - there is definitely improvement here. Still not fantastic improvement for basic WebCenter application, but at least improvement.

Next - WebCenter Composer opening. In PS5 is completed within 203 milliseconds:


In PS3 it was completed even in 180 milliseconds - no improvement for WebCenter Composer in PS5.

Add Content popup from WebCenter Composer is still not fast, opens in average 438 milliseconds:


If we compare this with regular ADF popup - it opens in 171 millisecond in PS5:


This makes me wonder, why it takes longer WebCenter to load static list of items into Add Content popup.

Something really fun now, simple ADF Task Flow opens in WebCenter Portal 11g PS5 in average 359 milliseconds (it was loading in 360 milliseconds in PS3 - almost no difference)


Exactly the same ADF Task Flow opens just in 282 milliseconds, when running from plain ADF application:


And this is plain ADF Task Flow, think about more complex cases. I think WebCenter Portal is slower to render ADF Task Flows, because its using separate navigation renderer to load ADF Task Flow - additionall processing doesn't come without cost - however this should be optimized and there should be no difference at least for simple ADF Task Flows. If your ADF Task Flow loads slow in WebCenter, this doesn't mean ADF is slow - there might be problems on the portal side.

If we switch from Portal view into Portal Administration Console - it loads average 1.13 seconds, 28 requests and 1.5 MB of data:


It loads same amount of data, each time we open Administration Console from the same session - is not optimized, probably because is doing redirect each time. Same applies for navigation back to Portal screen - each time it will perform complete initialization and load same amount 1.2 MB of data as during authentication:


Long story short - there are some performance improvements (authentication process is more optimized, a bit faster initial page load), but still there is room for improvement. I can give 7 points from 10 (this might be a bit too generous) for WebCenter 11g PS5 performance optimizations.

Friday, February 24, 2012

Update: How To Fix Data Control Initialization Error with ADF Libraries

This post is update for - How To Fix Data Control Initialization Error with ADF Libraries. It was described ADF Binding Context initialization problem with ADF Libraries and how to avoid it by calling initial Task Flow method through ADF Bindings. As per Frank Nimphius comment - You don't need to invoke a method. Having a PageDef file alone is sufficient for the Binding Context to be created. I have tested - indeed, this suggestion works great as well.

Download updated sample application - ADFIntegration_v3.zip.

To create empty Page Definition for Task Flow Method Call method invoking Java method, right click on Method Call and choose Create Page Definition option:


Empty Page Definition is created with mapping defined in DataBinding.cpx. I think, when there is Page Definition mapping in DataBindings.cpx - ADF is able to load all Data Controls from DataBindings.cpx properly and its why getApplicationModuleForDataControl('...') is not failing anymore:


Tuesday, February 21, 2012

How To Fix Data Control Initialization Error with ADF Libraries

If you are getting NullPointer exception from Data Control bindings, when integrating ADF Libraries into one single application, most likely Data Control method is accessed bypassing ADF Model layer. I have described this problem and solution back in 2009 - Integration in Oracle ADF Through ADF Libraries and ADF Task Flows. Long story short - NullPointer exception may happen when referencing Data Control directly, and when Data Control was not initialized yet. However, sometimes based on a use case - we need to call Data Control directly, for example from Task Flow initialization method (where we don't have access to Page Definition). This post will describe quite simple trick how to bypass Data Control initialization problem.

Download updated sample application - ADFIntegration_v2.zip.

Just to refresh your memory about original problem described in the blog post above. If there is Method Call activity in the Task Flow and this Method Call invokes Java method directly with access to Data Control:


You may get NullPointer exception, after such Task Flow will be integrated into main application. Keep in mind - Task Flow will work fine when testing it locally. Exception stack trace in my case:


Exception happens because we are calling getApplicationModuleForDataControl('...') method, it fails to locate Data Control entry in multi ADF library environment:


In case we still need to call getApplicationModuleForDataControl('...') method from specific Java method, before Data Control gets initialized - we can trick it by calling empty method through ADF Bindings just before the Java initialization method. Declare empty method in AM Implementation class and expose it through client interface:


Once this empty method is exposed and available in Data Control:


Invoke it through Method Call with ADF Bindings - just before the Java initialization Method Call:


This will ensure proper Data Control initialization for current Task Flow and getApplicationModuleForDataControl('...') method will be able to locate Data Control entry.

When running sample application, from main screen press First Remote button:


Task Flow is loading correctly, Data Control was located successfully from Java initialization method:


Sunday, February 19, 2012

ADF Page Template Refresh From ADF Page Fragment

I would like to describe how to refresh dynamic content available in ADF Page Template from consuming ADF Page Fragment. This is not always obvious, because physically ADF Page Template and ADF Page Fragment are two different files. However, this is possible by applying partial trigger on ADF Page Template binding tag inside ADF Page Fragment itself. This post is intended to show how to refresh ADF Page Template from ADF Page Fragment, use case about selected employee name retrieval can be implemented in different ways as well.

Sample application contains ADF Page Template with layout component, as well as with output text component to display template attribute value. This value will be changed from the consuming ADF Page Fragment - means we would need to trigger refresh in order to have it changed in ADF Page Template:


Output text gets its value from ADF Page Template attribute:


There is ADF Page Fragment, which is based on ADF Page Template and contains a button to store currently selected employee name into pageFlowScope. As you can see, there is ADF Page Template tag, but we dont have direct access to the UI component from this template - means we can't declare Partial Triggers from button:


What we can do - select af:pageTemplate tag:


Declare Partial Triggers for af:pageTemplate - its how we can refresh UI components defined in the template. Partial Triggers property points to the UI button component available in the ADF Page Fragment - its how we can refresh components in the template, from local button available in the fragment itself:


Button which triggers refresh, contains property listener, it stores selected employee name into pageFlowScope:


PageFlowScope variable is populated with selected employee last name value:


Value is propagated up to ADF Page Template and content is refreshed through PPR event raised from Set Employee button:


Download sample application - TemplateRefreshApp.zip.

Saturday, February 11, 2012

Many-to-Many Relationship Insert in ADF BC and ADF Faces UI

My last post was about how to implement Many-to-Many relationship in ADF BC and ADF UI - Many-to-Many Relationship Implementation in ADF BC and ADF Faces UI. I will continue the same topic and describe today how to implement Insert operation for Many-to-Many relationship.

Download developed sample application - ManyToManyADFBC_v2.zip. This sample is update for previous blog post application. It contains code to insert new records into Many-to-Many relationship.

There is Java method in Application Module implementation class, it inserts mapping row into relationship table (BlogsReaders) and commits transaction - this method is called from ViewController, after user submits new row for insert. Readers and Blogs VO's are refreshed after insert - to bring new mapping back to the UI:


I have defined two additional VO instances in Application Module for both ends (Blogs and Readers). This is required for better UI experience - while inserting new record, current records will stay in tact:


Managed Bean from ViewController contains two listeners - one to insert blank row and prepare data entry form, another is triggered when users confirms new record - it retrieves required ID mapping and calls method from Application Module to populate mapping table and complete transaction. This example is for Readers end, same is applied for Blogs end:


ADF binding view - 4 iterators to represent Many-to-Many relationship and 2 iterators for data entry:


On runtime it works like that - user adds new reader, data entry popup opens. New  reader entry is automatically associated with currently selected blog:


New reader - Sheldon is inserted, right side with related blog can be synched for new record:


In the same way, we can insert new blog:


Now user is reading two blogs:


If you will change a reader on the right side to Julia, blog list will be updated. However, if you would like to synch all readers from selected blog - click on blog row or press Synch button:


Readers list is in synch:

Saturday, February 4, 2012

Many-to-Many Relationship Implementation in ADF BC and ADF Faces UI

Is not always obvious how to implement Many-to-Many use case. I will describe how to represent Many-to-Many data structure in ADF BC and how to display it effectively with ADF Faces. With my next post I will provide another sample application to describe how to create and delete rows for Many-to-Many.

Sample application - ManyToManyADFBC.zip is based on custom DB schema, SQL scripts are included. Database schema is taken from old 2007 post - Many-to-Many mapping in Oracle TopLink:


When you generate ADF BC, it doesn't generate Many-to-Many associations for you by default - you will need to recreate them manually:


Define * to * cardinality for Blogs -> Readers relationship, select intersection key from central mapping table:


Do the same * to * cardinality for Readers -> Blogs relationship, select intersection key from central mapping table:


Define View Link for Blogs -> Readers based on existing Association:


Create View Link for Readers -> Blogs based on existing Association:


Application Module should contain Data Model for Blogs -> Readers and Readers -> Blogs:


While Application Module contains 4 View Object instances - ADF UI implements only 2 tables. One table displays Readers data, another Blogs:


Both tables are pointing to detail View Object instances. Detail data is refreshed from master View Object instance. Current row for master View Object instance is set through choice list selection. Once choice list selection is updated and master current row is changed - ADF UI automatically updates corresponding detail View Object collection:


As you will find in Page Definition, Readers table is populated from detail View Object instance:


Master choice list is mapped with master View Object instance - it controls Readers table:


One more cross selection event is implemented by overriding table selection listeners for both Readers and Blogs tables:


Listener gets currently selected row from the table and passing row key to update current row for master collection on other association end (it will update choice list).

This is how it looks on ADF UI - two tables from Many-to-Many relationship, together with master data choice lists:


User can change Reader choice list selection, Blogs table data will be updated:


When user is changing row selection in the table itself, for example Blogs - this triggers refresh for Blog choice list on the left and Readers table as well:


Same logic with Readers table - row selection triggers refresh for Reader choice list on the right and corresponding Blogs table: