Tuesday, 15 July 2014

Analysing ADF Requests in JDeveloper (11.1.1.7 and others)

Once again, there are plenty of blogs out there to tell you that you can use the "Oracle Diagnostic Log Analyzer" to see exactly what is going on in the background of your request (and there is a lot).

"Brilliant", you say, "I have been looking for such a tool...and its within JDev. Cool".

Until you come to use it in 11.1.1.7 (other versions might be affected) and you can't get the requests to show up in JDeveloper.

You might come across it when you carry out some requests and the Oracle Diagnostic Log Analyzer shows up "xxx requests found, 0 displayed"

Fret not...it's just a case of setting the logging. This also means you do not have to restart the integrated server, saving minutes of your day.

There was a forum question based on this - Why ODL is displaying nothing?

Step 1 - Open the logging.xml file
Ensure your integrated server is up and running and select "Configure Oracle Diagnostic Logging"







Step 2 - Add oracle.adfdiagnostics logger
Thanks to the useful videos at ADF Insider Essentials, one of the videos comments on adding this entry. Add a persistant logger so it doesnt always disappear upon server restart and type oracle.adfdiagnostics and set the level to Config











Step 3 - Set correct logging levels
You need to set 3 other logging levels as well as oracle.adfdiagnostics: oracle.adf, oracle.adfinternal and oracle.jbo. Set them all to Config also.















Step 4 - Open the Analyzer
There's a few ways you can open the Request Analyzer from within Jdeveloper - my preferred way is to go where we opened logging.xml from but choose "Analyze Log" --> "Current in Console"













Step 5 - Do Something!
Perform a request in your application.

Step 6 - Analyze
Click Search in the analyzer and you should now see your request with all the JDeveloper colour glory. Now you can pat yourself that this very easy task took a blog lookup to get working :-)










Happy Days.

Wednesday, 30 October 2013

Using a Task Flow Template

I decided to look into the task flow features of ADF and stumbled across the template feature. Basically a task flow can extend a template and then you don't have to worry about all of the nitty gritty bits that you may have to do everytime such as auditing or setting up values etc etc.
Templates are not shown in the main designer view of taskflows...they are kind of hidden.
Below, I will show you how to complete a certain set of activities within a template and then carry on your normal taskflow operation.

So to test this, I thought I would create a template which sets up a int value and then within my main task flow, show this value.

I created a managed bean with some methods which would be called from within the template:

The template looks like the following: nothing special here apart from the big gotcha with the 'Parent Action' activity, whereby only the outcome works BUT the compiler requests you to have either a root or parent outcome. Therefore, I have just put the same action within the root.


Note: When there is no class setup for a parameter, at runtime its looking for a method with a String.

We can listen out for when the task flow template has finished its work by using the wildcard control flow rule.


Note that there is no default activity here: this is because the default has been changed to run the template


Accessing the variables within the main Task Flow is easy as everything is within the same pageFlowScope.

When running this task flow, all the templates activites get run first and then myView runs inside the region, which puts out a variable within the pageFlowScope.

Summary of notes (11.1.1.6 JDeveloper):
  • When you create a Task Flow on a template, the templates input parameters are required to call the main Task Flow.
  • If you want the template to run its children first, you need to set the default activity within the main Task Flow
  • The Parent Action requires a Root or Parent Outcome but only the Outcome is used
  • Everything within the template and Task Flow are contained within the pageFlowScope

Tuesday, 30 July 2013

Understanding where code gets fired from

Problem: you use a component (in our case, a SelectOneBoolean) which has its selected value is stored within a bean. The setter to this gets called multiple times on a page load (this is normal) but during navigation of the page, the setter was being called from an unknown place, causing a bug in our UI.

Now, to solve this, you cant really use the debugger because you know where the problem lies, but you dont know the calling code.

A good solution, to understand the route of methods being called, is to introduce an exception. Its a strange concept but is good for things like this.

Add the following code to get a stack trace of the methods fired to give you a better understanding of what is going on within your ADF pages.

try {
    throw new Exception("");
} catch (Exception e){
    e.printStackTrace();
}

To clairfy, you simply generate an exception, print out the stack trace and carry on processing the application logic.

We eventually found the issue relatively quickly within one of the methods prior to the setter being called.

I hope this helps somebody; somebody scratching their head over a problem of "why and where is this being called from."


It shouldnt need to be said, but do +NOT+ go into production with these still present.

Friday, 28 June 2013

ADF on iPad and iPhone - Table data

We have uncovered a problem with using ADF inside the Apple mobile products, namely the iPad and iPhone.

The issue being that the data within a table is not fetched via AJAX when you scroll to the bottom of the table.

In reference to my post here about caching data in a table, http://everythingadf.blogspot.co.uk/2013/06/table-caching-in-your-jspx.html, this solution would pre load all rows and would potentially solve the problem for tables which hold an intermediate amount of data. The definition of intermediate being open but I feel around 200-500 rows is your limit.

Upon investigation, its because these devices do not actually have a scroll bar. It seems ADF is listening out for the scroll bar action to then fetch more data.

The solution to this is simple, and brings the iPad and iPhone back inline to how ADF normally acts; add the scrollbar back in.

This can be done in CSS using the following:

 <af:table value="#{bindings.CustomerSystemsVO1.collectionModel}"
    var="row" 
    inlineStyle="-webkit-overflow-scrolling: touch;"
    ...>

Thursday, 27 June 2013

Show popup when ADF is busy


There are times when you need to block all user entry when ADF is busy doing a long-running task.
I had this scenario with a long running synchronous call to a web service.

This operation was fired off from a command image link rather than a button

There is a property on the af:commandImageLink, blocking, which is supposed to turn the mouse pointer into an intermediate load state.

When testing this on a development server (i.e. not the JDeveloper integrated Weblogic), I found that it didnt truly block the user input. Also, its not totally clear that the users click was recognised by the app.

Therefore, the best way to do this is to show a popup. This will block all user input and we give a clear indication that the server is doing something.

Step 1) design your 'Loading' popup

You will need to set the contentDelivery to immediate so the popup is injected into the HTML as soon as its rendered out to the user. Speed is of the essence here and the server is busy with our request, so we need this to be pre-loaded.

Its nice to have a loading image too. Generate one from this website, which is free to use:
http://www.ajaxload.info/

<af:popup id="p7" contentDelivery="immediate" >
  <af:dialog id="d3" type="none" title="Loading" closeIconVisible="false">
  <af:panelGroupLayout id="pgl9" layout="scroll" halign="center">
    <af:outputText value="I am loading." id="ot78"/>
    <af:spacer width="10" height="10" id="s2"/>
    <af:image source="/images/ajax-loader.gif" id="i98" shortDesc="loading"/>
    <af:spacer width="10" height="10" id="s3"/>
    <af:outputText value="One moment please..." id="ot11"/>
   </af:panelGroupLayout>
   </af:dialog>
</af:popup>
 
Step 2) show your 'Loading' popup
When  the user clicks the image, I want the popup to show instantly. For this, we use javascript via the clientListener tag:

<af:commandImageLink icon=....
    <af:clientListener method="preventUserInput" type="action"/>
 </af:commandImageLink>

Step 3) javascript to handle the popup

This code handles the finding and showing of the popup as well as creating a busyStateListener which gets called when the loading operation is completed.

Up to this point, everything here can be seen on numerous ADF blogs but they do not discuss how to handle when errors are thrown from your long-running process. This is what the interruptBusyState is for.

Put the following code at the bottom of your JSPX as a resource (or externalise it into a seperate js file if you need it on multiple pages)

  <af:resource type="javascript"> 
     //interrupt handler
     function interruptBusyState(){
     var popup = AdfPage.PAGE.findComponentByAbsoluteId('pt1:p7');
     popup.hide();
     AdfPage.PAGE.removeBusyStateListener(popup, handleBusyState);
   }
       
     //JavaScript call back handler
    function handleBusyState(evt){
    var popup = this;
      if(popup != null){
        if (evt.isBusy()){
          popup.show();
        } else if (popup.isPopupVisible()) {
        popup.hide();
        AdfPage.PAGE.removeBusyStateListener(popup, handleBusyState);
        }
      }
    }
       
    function preventUserInput(evt){
      var popup = AdfPage.PAGE.findComponentByAbsoluteId('pt1:p7');
           
      if (popup != null){
                 AdfPage.PAGE.addBusyStateListener(popup,handleBusyState);
                evt.preventUserInput();
      }
   }
  </af:resource>


So, the preventUserInput method sets up the busy listener with the found popup. When the page is busy, it will run the handleBusyState will get called again when the operation completes and therefore the popup will be hidden.

Notice that we can reference the popup within the handleBusyState method by using this. The this object is created because we called handleBusyState with the popup

Step 4) handle errors in long-running process
If there is an error in your code, you may find that the popup doesnt close itself and that the exception appears behind the popup. This is unacceptable as the user is now stuck with a loading popup and cannot do anything about it.

In my backing bean, I have an operationBinding which executes my long running process. Here is the end of that method, testing to see if errors were raised and interrupting the loading popup if there was one:

if (ob.getErrors().size() == 0){
  return "showMultiplexConfiguration";
} else {
  logger.severe("serious error received in bean; stop the loader");
  interruptLoadingPopup();
}

       ...
       ...

private void interruptLoadingPopup(){
  String script = " interruptBusyState(); ";
  FacesContext fct = FacesContext.getCurrentInstance();
  Service.getRenderKitService(fct,
ExtendedRenderKitService.class).addScript(fct,                                                                  script.toString());



The private method interruptLoadingPopup does the work for us, calling the javascript interruptBusyState() method, as defined in step 3)

Final words
Its not the most fluid of solution because you need to locate the loader popup through its absolute location, but once this is done, its a neat solution that gives the user a full indication of what is going on.

As a side note; you cannot have dynamic content on the loader as its loaded immediately at inital render time. I.e you can have text saying "you clicked on row 3. Loading row 3".

To me, this is just a small caveat.

Happy coding.

Saturday, 22 June 2013

Table Caching in your JSPX

Task: To render a table in a JSPX page with all rows loaded in it. There should be no "Fetching" statements when the user scrolls up and down the table, which normally appears at row 25 onwards.


Easy, right?

In practice, this was harder than it seemed.

Most blogs will tell you that you simply go to the iterator and set the RangeSize to -1.
This is OK, as it ensures that the UI layer has all the rows from the model; perfect.

Upon testing this however, you still get the "Fetching Data..." or "Going to Row [n]" when scrolling down the list.

Hmm, whats causing this?

Well, first investigation was to print out the iterators rowsize in a backing bean, to ensure I had all the rows in the UI layer:

DCBindingContainer dcBindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry(); 

DCIteratorBinding iterBind= (DCIteratorBinding)dcBindings.get("EmployeesIterator");

System.out.println("EmployeesIterator: "+iterBind.getAllRowsInRange().length);

This was printing the expected result: 107 rows (running off the default hr schema).

So, back to the table and I noticed that there is a definition here to control the rows shown:

<af:table value="#{bindings.Employees.collectionModel}" var="row"
    rows="#{bindings.Employees.rangeSize}"
    emptyText="#{bindings.Employees.viewable ? 'No data to display.' : 'Access Denied.'}"
    fetchSize="#{bindings.Employees.rangeSize}" 
    rowBandingInterval="1" id="t1">

So, the table uses the iterators rangeSize to decide how many rows to show.
There must be a behind the scenes conversion that if this is -1, to use a value of 25.

We can dynamically set this value to another property off the iterator, estimatedRowCount, which will return us how many rows it has. Perfect.

My new table definition is now looking like this:
<af:table value="#{bindings.Employees.collectionModel}" var="row"
    rows="#{bindings.Employees.rangeSize}"
    emptyText="#{bindings.Employees.viewable ? 'No data to display.' : 'Access Denied.'}"
    fetchSize="#{bindings.Employees.estimatedRowCount}" 
    rowBandingInterval="1" id="t1">

Upon doing this, the scrollbar could be scrolled to the end and to the top without any further messages interrupting the user.

Thursday, 20 June 2013

Default Opening Mode in JDeveloper

Ever had that annoying thing where you open a file within JDeveloper to check just a line of source but it hangs on the Design mode, attempting to render out your really complex jspx?

Well, there is a setting to make sure that you open all files in the source viewer, not the designer.

To do this, go to Tools > Preferences > File Types, and click the 'Default Editors' tab on the right hand side.

Set the items you want to change and choose 'Source' from the combo box.
If you want to just change jspx files, like I did, find and change: JSP Segment.

Note: JDeveloper seems to remember what tab you closed the files with. Its only older files that will open with this view. If I find out how to clear that cache out, I will update the post.