Wednesday, June 24, 2015

Intercepting Table Filter Query and Manipulating VO SQL Statement

I’m going to describe one non declarative use case. Imagine, if there is a table with filter functionality, you may want to intercept filter items and apply the same for another VO. This another VO should be based on the same DB table, so it could apply criteria items against the table.

Sample application - AdvancedViewCriteriaApp.zip, implements a fragment with table component and a chart. Table component can be filtered, criteria is intercepted and applied for the chart, this one is rendered from different VO with GROUP BY query. Chart stays in synch and displays data according to the criteria filtered in the table:


In the log, I’m printing out intercepted criteria from the table filter:


Chart is rendered from the SQL query below:


Table filter criteria is being intercepted by overridden method buildViewCriteriaClauses. Criteria clause is constructed here, we just need select FilterViewCriteria, the one originating from table filter. We could apply this criteria straight ahead to the VO responsible to bring chart data. However, this would not work - ADF BC would wrap original chart SQL query with SELECT * FROM (…) QRSLT WHERE (table filter criteria). This would not work, because table filter criteria is not present in the original chart SQL statement. To make it work, I’m updating original SQL query for chart data, by updating WHERE clause part:


In the last step, we need to pass bind variable values - the ones user is searching for in table filter. This can be done from another overridden method - bindParametersForCollection. We have access to the applied bind variables in this method. Again, you should check for FilterViewCriteria and extract applied bind variables values. Chart VO will be updated with bind variable definitions created on the fly and assigned with values to search for:


I hope this trick will save some of your time, if you are going to implement something similar - to intercept table filter query and apply it to the another VO, based on same DB table.

Thursday, June 18, 2015

Select One Choice with Select Items Tag

If you need to implement select one choice based on alternative data sources (not based on ADF BC) - you shouldn't use af:forEach inside af:selectOneChoice component. Don't get confused with af:forEach tag, this tag is supposed to generate multiple components and not to iterate over a collection of objects and render HTML for each item. There could be cases, when choice list data will come duplicated, with af:forEach tag applied. I would suggest to construct array of SelectItem objects and return it to the f:selectItems tag to be rendered.

This is how proper af:selectOneChoice definition should look like. Array of items is being rendered in the choice list through f:selectItems tag:


Value property for f:selectItems can be entered manually or through the wizard, when creating af:selectOneChoice - this should point to the custom method, where array of SelectItem objects is constructed:


Custom method could read data from any source and construct array of SelectItem objects. This is the input for f:selectItems tag, it knows how to render a list of choice list items out of it:


This is how it looks on runtime - choice list is working fine, no need to use af:forEach:


Download sample application - CustomSelectListApp.zip.

Thursday, June 11, 2015

How To Record ADF Client Side Request Performance Time

I had a blog post, where I have described how to monitor client side request performance time with Ajax tag (works in ADF 12c) - Monitoring PPR Request Time on ADF UI Client Side. There is effective way to propagate recorded statistics back to the server for history logging using WebSockets - WebSocket Integration with ADF for PPR Request Monitoring. This requires WebSockets integration into project, if project doesn't allow this - there is another way. We could leverage Ajax call to the Java servlet and pass logged statistics data through parameter. I will describe how this can be achieved.

Sample application - ADFAltaApp_v6.zip, implements standard servlet. In the doGet method, I'm accessing parameter and parsing received statistics data. From here we could log data to the DB, so it could be analysed further. Data processing should be executed in the separate thread, not to block servlet execution and return response back to the client. Java in ADF 12c supports asynchronous servlets, however this is not the case with ADF 11g versions (unless you change JVM to 1.7). Parameter processing in the servlet:


On the client side, JavaScript code contains a method to acquire Ajax XmlHttpRequest object. Through this object we can invoke servlet, directly from JavaScript:


In the monitor function (invoked automatically on start and end events for the request) - we are invoking servlet and passing request performance data to log. I'm executing synchronous call, this is done on purpose - asynchronous calls in JavaScript can be lost, if user executes requests fast, portion of the data will be skipped. Synchronous call is made at the end of the request and usually is pretty fast (make sure to log data in the separate servlet thread, not to block execution):


This is how it works. Press Save button - you will see information about request processing time embedded in the top of the page (this is calculated and updated in JavaScript function from above):


Servlet on the server side prints received data to be logged - button ID, request processing time, user info:


Try to invoke another request - navigate back to the previous fragment. Time will be logged and displayed in the top part of the page, same is communicated to the servlet for logging:


Time is being logged on the server side:


I hope described idea will be useful for your own project, where you could measure ADF UI client performance (from button click, until action is done). Ajax tag to catch request start and stop events works only in ADF 12c, but you could do similar thing in ADF 11g with custom JavaScript listeners.

Thursday, June 4, 2015

How to Apply New Label Text in MDS Customisation

It may look simple, but really is not obvious how to apply new label text for the ADF BC attribute or UI component through MDS customisation. It is simple, if such label text already exists in the core bundle. If you need to create new label text in the customisation and use it - this becomes a bit tricky. Well, as usual - I'm going to explain how you could solve such task. You should read more about MDS customisation setup in ADF - MDS Seeded Customization Approach with Empty External Project.

Core application - mds_label_cust.zip, contains one label for First Name VO attribute:


The requirement is to customise core application and add label for the Last Name VO attribute, without changing anything in the core. For this purpose, we need to create different JDEV application - extension, configured with shared library deployment profile. Here you could simply create new properties file. We are going to use this application to deliver additional components for the core. Keep in mind - core application must be configured to use this library. Add label for Last Name VO attribute, in the properties file located in the extension:


Time for the main trick. We could use label directly from any resource bundle in the ADF application. This is accomplished through such expression - reference for the resource bundle and label key:


This code should be part of customisation project, on runtime it will find referenced resource bundle and label key in the resource bundle from extension (see above).

This is how it looks on runtime - label text is taken from resource bundle in extension and applied by customisation:


It sounds more tricky, than it is - just try it.