Thursday, November 3, 2011

ADF Security Basics

ADF security is a pretty deep topic especially when you put it in perspective of an enterprise deployment and how the security infrastructure works together with the application server to provide for the functionality. Also, there are a number of great resources out there that give a good understanding about how to configure and secure an ADF application. My first go-to resources on the web would be :

Oracle ADF Documentation : Section 35
Chris Muir's Blog Post

Having said that, this is a quick look at the various aspects included in ADF Security  and a rundown of whats possible with ADF security and how to implement some fairly common use cases.  The example is based on the HR schema and can be downloaded from here.

In its simplest form, ADF security is declarative and protects pageDef files( for pages in the Unbounded taskflow) and whole BTFs (Bounded Taskflows), it can also be applied to EOs and EO attributes, which I personally consider especially powerful when combined with Oracle Database's VPD feature ( maybe that's a good topic for a blog post ! ).

ADF security is based on OPSS which in turn is based on JAAS. In this model, we create "application roles" and grant permissions to application roles to do certain operations within the application and hence the name. So the ability to do a set of operations is collected and called a role. Now these roles are granted to specific users, which enable those users to do all the actions defined by those roles assigned to them. In a real production environment however, the users are not defined in the context of a single application, instead they would be defined for the whole enterprise and granted access to various applications, all using the same user name (a single sign-on or SSO). So these identities (or users) would be defined in an identity store like LDAP and WLS can work with such systems. In WLS we can create "enterprise roles" which is very similar to application roles, but are defined at the container (app server) level, and so all applications can use them. Therefore, in a production setup, we also have to map application roles to enterprise roles (for each application) and then associate users to the enterprise roles. This makes it possible for developers to develop applications without worrying about enterprise roles or application roles used by other teams and products.

By default when we enable ADF security , the bounded taskflows and the pagedefs for the pages in the unbounded taskflows are secured. The UBTF is not security aware and cannot be secured as a whole like the BTFs. Entity objects and EO attributes are not secured by default, and requires a grant to be given explicitly.

Tip :  to secure a page that does not use the ADF bindings, we can just create an empty pageDef file by right-clicking the page and choosing "Go to PageDef" . This empty pageDef can then be used to secure the page.

EO (and therefore editable VOs) can also be secured on the basis of application roles. Security is applied on two levels for an EO. On the EO as a whole or on a specific property of the EO. For the whole EO, security permissions exist to restrict read,update and delete on the EO. For EO attributes the permission exists to secure the update operation on any field. Column-wise security can be done on the View layer by toggling the visibility of a table column based on a security EL.

More Details & Example Application

The example application tries to demonstrate various use cases and how to secure various parts and pages in an application.The example is built on the standard HR schema and has two bounded task flows apart from the default unbounded task flow. The example has a landing page, and a taskflow to maintain (Search & Edit) Employees and another taskflow to maintain Departments.


For the example, we shall define the following Application roles in our application :

  • EmployeeAccess - can view MaintainEmployees taskflow
  • DepartmentAccess - can view MainatinDepartments taskflow
  • EmpManager - can edit employee details (except salary)
  • DeptManager - can edit department details
  • SalaryManager - can edit salary for employees
 For the purpose of demonstrating various cases, the task flow is structured as below :


The Landing Page
 The landing page, Welcome.jspx,  is accessible for everyone, but also contains an embedded taskflow that is displayed only to authenticated users who have access to view it. There are links on the welcome page that take the user to other pages and require the user to authenticate before the page is displayed to them. The other pages to search for and edit employees and departments, require the user to have various access levels to perform various actions.Welcome.jspx is a publicly accessible page. It is made public by granting 'view' access on this page, to the 'anonymous-role' built in role. To do this, open your jazn-data.xml and follow the steps below :

The jazn-data.xml editor allows you to associate roles to pages/taskflows

The same dialog is used to set permissions for taskflows (change dropdown marked "1" from webpage to Taskflow). The roles defined will be shown in area marked "3".

In the UI pages we can use the security EL to show hide fields or to make then editable and non editable. If you open the expression builder you will see the securityContext object in the bindings object with a number of very useful methods in it.
Notice the expression to check if the user has permission to view a taskflow, and also the various methods exposed by the securityContext object(click to enlarge)


On the welcome page the following EL is used to render the bounded taskflow as a region


This EL basically checks if the logged in user has access to see the taslflow. The taskflow is referenced by giving the path to the taskflow xml file (relative to the WEB-INF directory) followed by the taskflow name.


At this point its worthwhile to note that permissions are usually hierarchical in nature. The role that can edit the salary for an employee would surely have the permissions to edit and view employees. So in our case the permissions would be like this :
Hierarchical Permissions


The Maintain Departments Page
The MainatainDepartments page and taskflow are secured and is available to authenticated users who have the DepartmentAccess permission or above (see the permission hierarchy above ). With the DepartmentAccess permission the users can search departments and view details, but cannot edit anything, because we will ensure that components are editable only based on the permissions granted to the logged-in user. To edit a department, the user needs the DeptManager  permission. This taskflow is also calledby the edit employee taskflow where an employee who has the permission to edit departments can directly edit a department.
-
The Maintain Departments BTF supports parameters to directly show the edit page for a given department.
The Maintain Employees page
The Maintain Employees page and taskflow are also secured and accessible to people with appropriate permissions. Just like Departments, the user needs an EmployeeAccess  permission to view , and an EmpManager permission to edit details. But in this case, we implement EO level security, by requiring the some users to also have a SalaryManager permission to edit a user's salary. The  permission hierarchy screenshot above should make better sense now. SalaryManager gets to everything, the next lower permission, EmpManager gets to edit everything but the salary, and the lowest permission EmpAccess allows only readonly access The taskflow diagram is below :

The Mainatain Employees BTF is simple and has a taskflow call to directly edit Departments.
The EO level security for the salary is set by selecting the EO attribute to enable security on it.
Enabling security on EO attributes.
Once security is enabled, you need to associate roles to it, or no one will be able to edit this attribute.
This is a little tricky just because the JDeveloper menu is very well hidden !
To associate the roles do this :
Select the EO in the navigator window

Right click the EO attribute in the structure window to get the "Edit Authorization" Menu
This opens up the following dialog :

In this dialog, the application roles are displayed and you can grant the permission to the roles you select.

Showing/Hiding UI elements based on permissions
 Since we mostly use EL to check for permissions and decide whether or not to display some attribute, or set the readOnly property, having this hierarchical form is very beneficial as you see below. The code below is for the first column in the result table on the employee search. This column will render a link which can be clicked to view the employee details and edit them for an 'EmpManager' role, but will render as read only text for people with 'EmployeeAccess'. Now from the hierarchy we have, there is another level above 'EmpManager' and that is 'SalaryManger'. This higher level also needs to be able to edit employee information because by definition, the 'Salary Manager' can do whatever the roles below it can do, plus something extra (edit salary, EO level security in this case). So the EL securityContext.userInRole[''] will return true for and any if its parent roles. So in this case, when a user with the role 'SalaryManager' logs in he sees the link and not the readonly text becasue the expression will return true since 'SalaryManager' is a parent role of 'EmpManager'.

See the highligted EL expressions to see how application roles are referenced

That all the basics. What we have not looked at here is the integration with the WLS security infrastructure and Identity & Access Management tools like LDAP, OID and OAM.

You can download the source code here : http://myadfnotebook.googlecode.com/files/SecurityDemo.zip
To run the project, you can run the Welcome.jspx page. You will notice that some Authorization exceptions are not handled. These were left to demonstrate what happens when an authenticated user tries to access a page he is not authorized for. The exceptions can be handled by exception activities in the task flow , or the navigation links can be shows or hidden based on the authorization of a user.

By default the following users are configured (see jazn-data.xml to view/change these) :
User                  Password                   Role
department        weblogic123              DepartmentAccess
Dmanager         weblogic123              DeptManager
employee          weblogic123              EmployeeAccess
Emanager         weblogic123              EmpManager
empdept           weblogic123              DepartmentAccess & EmployeeAccess
Smanager         weblogic123              SalaryManager

Sunday, October 30, 2011

Get the ID/String Value for an LOV drop-down item though EL


In a previous post we looked at how to get the selected value or text from an LOV in our backing bean. While that approach is effective for most use-cases, there are some situations where you cannot use that approach , or using it is too cumbersome.In this post we'll look at a slightly different approach that can be used when you need to use the ID or String value in EL or you don't want to have a backing bean.

Needing to get the value in EL can be a common scenario when you are trying to extract the selected ID behind an LOV and pass it somewhere, like passing the ID to another bounded task flow. Very common use-case.

To consider an example, suppose you have an app built on the EMP and DEPT tables and you have an "Employee Edit" page. On this page, you have the department the employee belongs to, implmented as a drop down list of Departments ( LOV ). Now lets say you want to have an "Edit Dept" button next to the Department drop-down, which when clicked should take you to an "Edit Dept" page for the currently selected dept in the drop-down. This LOV drop-down on the "Edit Employee" page was created on the EMP VO, for the Dept ID attribute and would use a view-accessor on the EmpVO to map the Dept ID in the Emp Table with the Dept ID in the Dept table and pull the Dept name from that. What we need is the Department ID of the department selected in the drop-down so that we can pull up that department details in the "Department Edit" page when the user selects a department and clicks on "Edit Department".

The LOV when placed on a page, creates a list binding in the binding layer by default and as such is not very useful for us because it stores the index of the selected Item and not the underlying ID. The easiest method to get the current ID is to manually create an Attribute Binding in the pageDef that points to the DeptID on the same iterator that the list binding is pointing to. This means that when the user changes the selection in the LOV, the currency in the iterator will change and since the attribute binding is on the same iterator, the attribute binding will also change.

To get the value in EL, just refer to the attribute binding in EL and not the list binding .
Simple !

Sample application

I'm gonna re-use the sample application from the ADF Security Basics post.
http://myadfnotebook.googlecode.com/files/SecurityDemo.zip
In this application, there is a feature when editing an employee there is s a link go to the edit department page (from the employee detail page). This page has a drop down allowing you to select a department for the employee, but also a link on the side directly takes you to edit the selected department. This link is implemented using the approach described here.

Thursday, September 29, 2011

<af:query> loading screen / spinner pop-up v2.0

This is an update/follow up on a previous post about displaying a spinner or loading screen while a query is in progress. The original post can be found here. This post describes a much simpler method for getting the same result, and addresses a flaw in the original approach. Its a direct adaptation of the method described by Frank Nimphius in the ADF Code corner example.

The general idea here is to

  1. Execute a custom piece of JavaScript code when user hits 'Search' in af:query
  2. In our JS code, add a busy state listener to fire when the busy state changes.
  3. Show hide a popup based on the busy state.

The ADF code corner example is based on a normal command button. But in the case of af:query we don't have access to the command button that fires the search. In this case, we can use a Client Listener on the af:query that fires on the "query" event.  like below :


       



The example above, the JavaScript function 'fireLoadingScreen' is a custom JavaScript function and  is implemented as below :

          function fireLoadingScreen(evt){
            var source = evt.getSource();
            var popup = AdfPage.PAGE.findComponentByAbsoluteId('spinnerPopUp');
            if(popup != null ){
              AdfPage.PAGE.addBusyStateListener(popup,handleBusyState);        
              evt.preventUserInput();
            }
          }
          
          function handleBusyState(evt){
            var popup = AdfPage.PAGE.findComponentByAbsoluteId('spinnerPopUp');        
            if(popup!=null){
              if (evt.isBusy()){
                popup.show();   
              }
              else if (popup.isPopupVisible()) {
                popup.hide();
                AdfPage.PAGE.removeBusyStateListener(popup,handleBusyState);
              }
            }
          }



The complete example can be downloaded from here : http://myadfnotebook.googlecode.com/files/LoadingScreen2.0.zip

One word of caution. There are implications to using AdfPage.PAGE.findComponent in conjunction with JSF fragments. One way of working around the limitation described in this previous post is to use  

function fireLoadingScreen(evt){
        var source = event.getSource();
        var popup = source.findComponent('spinnerPopUp');
        if(popup != null ){
            popup.show();
        }
        

This uses the source UIComponent object to search for the popup component (not from the root of the document). So the search is relative to the af:query. But now you'd have no way to close the popup but to use the old backing bean based method though.

For those interested, lets look at what was actually wrong with the original approach ( other than being very convoluted )...
While the original post still holds good for a lot of situations (especially if you use jsff and are deploying the app as a portlet) , when specifically applied to af:query, it has one drawback that I recently came to know about. This drawback will be apparent only in a load balanced and highly available environment. If you use a load balancer or fail-over system, there is a chance that the user's session might be migrated to another server while a query is happening. When that happens, things go bad if you use the approach detailed in the older post . Lets see why.


Flow of events for the original solution


The original approach can be applied generically to normal command components or af:query (though there are other more declarative ways of doing this with command components). This method is useful if upon clicking a command component if you want to execute some logic in your backing bean to choose a specific pop-up/loading screen (our customers wanted different types of loading screens for various types of input specified by the user in the af:query ). What makes the implementation different for af:query vs. a normal command button is that in af:query you don't have direct access to the search button (unlike a normal command button). So we had to intercept the search action and hook in to it (step 1). The idea was to fire a user-input blocking pop-up by hooking in to the search action (but not start the search yet) (step 2), then fire the actual search from the pop-up once its visible (steps 3,4,5). In doing that we had to save the QueryEvent as a member variable in the backing bean. The query event would be provided to the method registered as the query listener (step 1), but since we don't actually do the query from that method(we just launch the popup from here) and fire the actual query from the pop-up using a second method(step 6), we need to make the QueryEvent object available to that second method (in step 6). And this is not a simple case of calling one method and passing a parameter to it. The second method is invoked using java script code to call back the backing bean. So we had to store the QueryEvent object and guess what, it is not Serializable ! So in the event a session is replicated, the serialization of the backing bean would fail. At this point one might think we can just make the QueryEvent transient and get around the serialization; But that door opens to a far more subtle and dangerous problem. Suppose we mark it transient, and there are a thousands of users on our load balanced system executing searches. The load balancer decides to move some sessions across to another server, and lets say it just happens to pick a session where a user just clicked the search button, and we've just saved the QueryEvent and opened our loading screen popup (step 1 complete). The entire session is serialized and replicated on the second server, and when the session is inflated on the second server, since we marked the QueryEvent as transient , the QueryEvent is set to null on the second server. Now things resume, but when we reach step 6 in our flow, instead of seeing a QueryEvent we would see null. What makes this problem really frustrating is that since the load balancer is involved, the issue will not be easily reproducible and it would be very difficult to trace.

As you can see, the new solution makes the whole process a lot simpler actually. As long as you have a single loading screen you want to display whenever the search button is hit, this solution is much better that the original one. 

Friday, September 23, 2011

Gotcha when executing Javascript from a backing bean.

Earlier I had discussed about how to inject and fire JavaScript on the browser from a backing bean. This is an invaluable tool for some corner cases and can make life easier , however there is a gotcha here when we try to do things in a sequential order after we inject the JavaScript. Its a subtlety that would go unnoticed for most people too, so that makes it noteworthy since knowing this can save us a lot of time spent on debugging.

Take a look at the code below : 
FacesContext fctx = FacesContext.getCurrentInstance();
StringBuilder script = new StringBuilder();
script = script.append("alert('Calling Service');");
Service.getRenderKitService(fctx,ExtendedRenderKitService.class)
.addScript(fctx,script.toString());


The code when set as the action for a command component will execute and display a browser dialog with the message "Calling Service". Lets say there are things you want to execute after the browser popup is launched like call a WebService or execute a query. So you make the code :
FacesContext fctx = FacesContext.getCurrentInstance();
StringBuilder script = new StringBuilder();
script = script.append("alert('Calling Service');");
Service.getRenderKitService(fctx,ExtendedRenderKitService.class)
.addScript(fctx,script.toString());
WebServiceProxy.invokeWSmethod() // assume we call a synchronous WebService.


What one might expect to happen is for the message to appear and the web service to be invoked(in that order). But what happens in reality is that the web service is invoked and then the message appears.This is because the java script is executed only after the method finishes (I'm assuming here that it executes when the call stack is empty). This order of execution is relevant when we want to use JavaScript to show a dialog or an af:popup that should be triggered first(executed on the browser) before executing an operation. The obvious solution for this would be to split up the javascript and the actual operation in to two methods on your backing bean and just run the JavaScript part first and then use a call back method in your backing bean (using a server listener) to run the actual operation. A good example of how this can be done in practice is described here.

Thursday, September 22, 2011

Gotcha when using AdfPage.PAGE to find components on your page

When using JavaScript with ADF, the AdfPage.PAGE.findComponentByAbsoluteId() and AdfPage.PAGE.findComponent() and invaluable tools. But there is a watch-out when using them in certain situations.  If you use JSF fragments , and probably you do (if you don't, then probably you should), then these functions might give you trouble. You might not be able to find the component (returns null/undefined) . In this case, you can try to look at the region that using your task flow and try to reconstruct the ID you need to be looking for. For example, if the ID for a command button is 'button1' and the jsff is in a task flow and the task flow is in a region with ID 'region1' on a jspx, then inspecting the button from firebug using Firefox, I would see 'region1:0:button1' . You could use that in your JavaScript, but  I don't really like that path though, because, if you end up portletizing your app, then you no longer have a .jspx, that would be created elsewhere, and you may not know/cannot depend on the how the actual run-time layout of the ID is going to be. The bottom line is you would need a backing bean method to find the actual run time ID of the component and then pass that to these functions. So effectively your Javascript gets moved in to the backing bean and you would be generating it at run-time (getting the real run-time IDs and setting them in to the function calls) and injecting the JavaScript and running it. Something like this would do the trick (example is from this post and it finds the actual ID for an af:popup on the page and calls popup.show() or popup.hide() ) :
public void toggleBusyPopup(boolean isShown){
    FacesContext context = FacesContext.getCurrentInstance();
    RichPopup popup = (RichPopup) JSFUtils.findComponent("busyPopup");
    ExtendedRenderKitService service =
      Service.getRenderKitService(context, ExtendedRenderKitService.class);
    if (isShown){
      service.addScript(context,
                        "var popup = AdfPage.PAGE.findComponent(\"" +
                        popup.getClientId(context) + "\"); popup.show();");
    }
    else{
      service.addScript(context,
                        "var popup = AdfPage.PAGE.findComponent(\"" +
                        popup.getClientId(context) + "\"); popup.hide();");
    }
    return;
  }

Friday, May 20, 2011

Making the 'Reset' button in af:query component clear the existing results from the result table.

Problem :  Clicking the 'Reset' button in an af:query does not clear the previous result rows from the result table.

Solution : Implement a QueryOperationListener and call executeEmptyRowSet() on the viewObject that back up the result table and the query.
This seems to be an often requested feature, and I guess it originates from the user's expectation from what a button called "Reset" should do when clicked. In a lot of cases the af:query component is accompanied by a result table and the user expects the data from a previous query to be cleared from the table when the 'Reset' button on the query component is clicked. This however is not the default behaviour, and clicking the 'Reset' button only clears the query criteria entered. So lets get on with it...


First define a QueryOperationListener for the af:query component. You will implement this as a backing bean method.



The backing bean code can be like this :

public void processQueryOperation(QueryOperationEvent queryOperationEvent)
  { 
    //This is to make sure that we don't just trap the call. 
    invokeMethodExpression(
             "#{bindings.//Your_search_binding//.processQueryOperation}",
              Object.class, 
              QueryOperationEvent.class,
              queryOperationEvent);

    if (Operation.RESET.name().equals(queryOperationEvent.getOperation().name()))
    {

      DCBindingContainer bindingContainer = (DCBindingContainer)
                            JSFUtils.resolveExpression("#{bindings}");
      DCIteratorBinding iter =
                         bindingContainer.findIteratorBinding(
                                            //name_of_the_VO_iterator//);
      // we have the iterator 
      // now get the VO and execute the empty RowSet to clear it
      iter.getViewObject().executeEmptyRowSet();

      // Now that the rows are cleared from the VO, referesh the UI Table.
      AdfFacesContext.getCurrentInstance()
                      .addPartialTarget(JSFUtils.findComponent(
                                                  "//ID of the af:table// "));

    }

Details on invokeMethodExpression can be found here, and replace the name of your searchBinding (you can find it from the page def's executables section) in the call to invokeMethodExpression.
JSFUtils is part of the ADF demo app from Oracle. Its a pretty good idea to have this in your project as a helper class. You should replace the name of your VO's ierator (you can find this out from the pageDef's executables section) and the ID of the af:table.

Wednesday, January 19, 2011

ADF printable pages : Fetching more data / rows for displaying a printable page

The Problem
When we use the built-in features to render printable pages, we are not making any additional server hits, say, to fetch all rows in a table that is to be included in the printable version of a page. In some cases we may want to have an entirely different layout for the printable version of the page, with additional disclaimer text and other elements.
The Solution
Use an alternative OutputMode to programmatically cause the printable page behavior.
The <af:showPrintablePageBehavior/>does not handle our requirement to hit the server for additional data, the alternative approach would be (depending on your scenario) to use a duplicate page with "email" features that mimics the features of the original page, but with layout that is more printer friendly. Enabling the email features renders the pages exactly as the <af:showPrintablePageBehavior/> would. To do this, you can pretty much copy paste your code as another page(You'll need the pageDef and other related files too), and if you are having a bounded taskflow with jsffs, then the printable page should be a view activity in the unbounded taskflow that can is marked as "Bookmarkable" with parameters,  so that the page can take the parameters and load all the data necessary. In the printable page, make sure that the 
  • data table content delivery is set to immediate and 
  • the AutoHeightRows is set to the FetchSize and 
  • the FetchSize is -1 so that all rows will be populated in to the VO that is backing the table.
This way you don't have to tweak the VO itself, but force to fetch all rows for the printable version of the page. Its definitely a performance hit if you are printing huge tables, in which case exporting the data as excel/html may be a more attractive solution.

Once the new "Printable" page is designed, running it in isolation may look fine, but when printing you wil notice that a true printable page behaviour is not produced. eg.: On screen, a table may display 50 rows, but on the paper, it may get truncated at 10. The new page is designed to hit the server to get all the data that we need to display in the printable version of a page. To make it behave like a page produced by the <af:showPrintablePageBehavior/>, we change the OutputMode mark the page as "Email-able" which renders the page in look and behavior like <af:showPrintablePageBehavior/>
You notify the ADF Faces framework to convert your page to be email/printer friendly by appending the following the request parameter to the URL for the page:
org.apache.myfaces.trinidad.agent.email=true
This causes the page to be rendered as a printable page
You can launch the page in  another window by setting the useWindow attribute on the command component to launch a new window/tab in the browser with the printable page. When launching the Printable page, you can include the URL parameters to load the data along with the org.apache.myfaces.trinidad.agent.email parameter.

This works well when you all the details on the printable page can be fetched with a few parameters. The most common example is when you have a master-detail or search/result type page navigation where you have one page that displays a number of records and you choose one record to view in deatil and you need to print the detailed information of that one entity/record (the details page). In this case, the details/Printable page can take one ID chosen from the master/parent/search page and then fetch all related information using that ID in the second page. If however the situation is when a search page is to be made printable, the usual case is that the use wants to save the results from his/her search and exporting the content as excel/html works better.

Thursday, January 13, 2011

ADF query component ( <af:query> ) with a loading screen / spinner pop-up (Updated)


New updated alternative approach here 
The problem
I have an <af:query> component that displays query results in an <af:table> on my page. When the user hits the search button, I need to display loading screen that displays a loading animation and blocks user input.


The solution
Use  a pop-up to display a spinner while the query executes.


Before you proceed with implementing this approach,  there is another much much simpler possible solution. If displaying an animation to indicate that the query is being processed is all you need, then <af:statusIndicator> may be an option. It is extremely simple to use : Just drop the tag on to when you want the spinner to appear and you’re done. This however, does not prevent user input during the query execution and the spinner will be activated on all server calls. The pop-up approach detailed below is more complex but allows much more control over the whole process.

The rough idea is to :
  1. Intercept the Query/Search action in a backing bean.
  2. Launch a pop-up blocking user input and showing a loading message/spinner
  3. Fire the actual query to the database and close pop-up when query is done.

The finer detail is a bit more involved :
  1. Intercept the Query/Search action
Implement a query listener for the <af:query> component in your backing bean.
<af:query id="qryId1" 
          headerText="Search" disclosed="true"
          value="#{bindings.EmployeeSearchQuery.queryDescriptor}"
          model="#{bindings.EmployeeSearchQuery.queryModel}"                      
          resultComponentId="::resId1"
          queryListener="#{pageFlowScope.testBean.processQuery}"/>
public void processQuery(QueryEvent queryEvent)
  {
    setQEvent(queryEvent); //Save the query event for the method that really fires the query to use.
    toggleBusyPopup(true); //Fires a popup, which inturn fires a serverListener.
  }

  1. Launch the pop-up from the backing bean with Javascript :
public void toggleBusyPopup(boolean isShown){
    FacesContext context = FacesContext.getCurrentInstance();
    RichPopup popup = (RichPopup) JSFUtils.findComponent("busyPopup");
    ExtendedRenderKitService service =
      Service.getRenderKitService(context, ExtendedRenderKitService.class);
    if (isShown){
      service.addScript(context,
                        "var popup = AdfPage.PAGE.findComponent(\"" +
                        popup.getClientId(context) + "\"); popup.show();");
    }
    else{
      service.addScript(context,
                        "var popup = AdfPage.PAGE.findComponent(\"" +
                        popup.getClientId(context) + "\"); popup.hide();");
    }
    return;
  }

  1. Fire the actual query to the database and close pop-up when query is done
You need to fire the query and keep the pop-up open as long as the query executes.
  1. To fire the query, from within the pop-up, use an <af:clientListener> to trigger a Javascript function on the page.
  2. ...
    <af:popup id="busyPopup" clientComponent="true">
              <af:clientListener method="onPopupOpened" type="popupOpened"/>
    ...
    
  3. This Javascript method will in turn  trigger an <af:serverListener> inside the pop-up that will execute a method on the backing bean.
  4. <af:resource type="javascript">
            function onPopupOpened(event)
            {
              AdfCustomEvent.queue(event.getSource(), "popupOpenListner", 
              { }, false);
            }      
    </af:resource>
    
    <af:popup id="busyPopup" clientComponent="true">
              <af:clientListener method="onPopupOpened" type="popupOpened"/>
              <af:serverListener type="popupOpenListner"
                                 method="#{pageFlowScope.testBean.processSearchQuery}"/>
    
  5. The backing bean method will fire the actual query
  6. When the query is done, the same backing bean method will update the result table and hide the loading screen popup.
  7. public void processSearchQuery(ClientEvent clientEvent)
      {
        // Do query : //
        invokeMethodExpression("#{bindings.EmployeeSearchQuery.processQuery}",
                               Object.class, QueryEvent.class, getQEvent());
        AdfFacesContext.getCurrentInstance().addPartialTarget(JSFUtils.findComponent("resId1"));
        toggleBusyPopup(false);
      }
    



Running the example application.

You can download the application from here.
To run it, unzip the files and open the project in Jdeveloper.
Run the test.jspx by navigating to  ViewController > Web Content > test.jspx Right-Click > Run