Tuesday, September 15, 2020

Migrating the view layer

Convert project to Facelets


1. Open the application which you would like to migrate

2. Select the view controller project and right click, from the menu select Convert to Facelets

3. Select Change Page Extensions and click preview in log

4.  


5. If everything goes well all the files would be converted into facelets and success message should be displayed.

6. Go to view controller and you should notice all the .jspx files are converted into .jsf files and .jsff stays the same.

7. This converter changes the tags in the header of the pages and fragments, adapts the libraries in the ViewController project.

8. New headline in a page based on Facelets:

<ui:composition xmlns:af=http://xmlns.oracle.com/adf/faces/rich xmlns:f="http://java.sun.com/jsf/core" xmlns:dvt="http://xmlns.oracle.com/dss/adf/faces" xmlns:ui="http://java.sun.com/jsf/facelets">


Old headline in a page based in JSP:


<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1" xmlns:af="http://xmlns.oracle.com/adf/faces/rich" xmlns:f="http://java.sun.com/jsf/core" xmlns:dvt="http://xmlns.oracle.com/dss/adf/faces" xmlns


Properties File

You have to take care about the used resource bundles inside a page. 

After conversion sometimes the entry of the variable which point to the correct resource bundle file is missing or the resource bundle is not recognized (highlighted with yellow warning in jdeveloper). 

If the resource bundle entry is available and the warning is issued, then delete the <c:set> entry of the resource bundle at the top of the page fragment.

You have to add one label of a component via the “Select Resource” wizard – afterward the entry is available again.

A new entry is added with the resource bundle and the values from properties file should be recognised by jdeveloper.

Migration ADF 11g to 12c - Issues and Possible solutions

 One of the clients I am working with had to migrate to ADF 12c from ADF 11g.  The migration process was not straight forward as expected. We faced many issues and had to apply several workarounds to get the application working.

I will be updating this blog with the process, issues faced and the workarounds used to overcome those issues.

Please find below the an overview of the issues.

1. Deprecated Classes

2. Issues with Templates 

3. Facelets Conversions

4. Deprecated Components

5. LDAP connection fails with "javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure"

6. Logout method deprecated

7. Filter Criteria deprecated

8. View objects broken – This one is intermittent, not all of them are broken.

9. Transient Expressions

10. java.lang.IllegalArgumentException: Script text to compile cannot be null!

11. invokeAction

For the ease of understanding I have divided the migration process into two sections
  • Migrating the View Layer
  • Migrating the Model Layer 

Thursday, October 27, 2016

Issue with ADF Popup Fetch Listener

Issue when popup fetch listener is added

Issue


  While working with ADF popup the developer wanted to use ADF buttons instead of the default buttons generated by af:dialog. 

 Method binding for  Popup fetch listener was added on af:popup

  Dialog type was set to none and two command buttons (Save and Cancel) were placed in the af:dialog .

 Save button was data bind with Commit operation and for Cancel an action listener method was added which is placed in Managed bean.

Code in the page now should look like the below screenshot.







Once the user clicks on Save and Close, it was all fine, the records were saved to the database and reflected in the UI.

But the issue was with Delete button, the action listener was never called. At first I thought I missed the debug code :) but to my dismay it was not the case.

After much of debugging I realised that there is nothing wrong with the button nor the action listener method.

Solution


Removed the method binding for popup fetch listener and the delete button started to work as expected.

I am not sure whether this is the solution or this is the way af:popup/af:dialog works.  I might be very naive in not knowing this behaviour as well.

Thursday, June 16, 2016

Shared Libraries - Wrong page displayed at runtime.

Problem :  While fixing a bug, one of the developers was changing the page to add a new attribute and some validation.  While running from local JDeveloper everything was fine, all the changes were replicated and the page was behaving properly, but as soon as we deploy it on the standalone weblogic server as a shared library the changes were not seen.

Solution: 

To investigate the solution, I have started looking at the problem.

1. Being deployed as shared libraries, the initial thought was the shared library is not built properly and hence the behaviour.

  - Cleared all the classes, deleted the shared libraries, re-generated the library and deployed again but still the same behaviour.

2. Now the next thought was the manifest version of the shared library was not correct and it is still taking the code from old version of shared library

 - Checked the manifest version on the server, everything looked fine, but still same behaviour.

3.  It was a random thought and started looking for the page name (in which developer was making the changes)eg., employee.jsff in the entire application.
 
  - Found instances of the same page name at the same path in a different application as of the page on which the developer is working.

Please find the path of the page fragments in both the applications.
 

Application 1

App1ViewController
-Applciation Sources
  - Fragments
      - EmployeePageDef.xml
-Web Content
  - Fragments
     - Employee.jsff


Application 2

App2ViewController
-Applciation Sources
  - Fragments
      - EmployeePageDef.xml
-Web Content
  - Fragments
     - Employee.jsff

Now I went to change the label of a attribute in the page of application 2 and redeployed the shared library.

And wonder what, the changes started to show up.

And finally the random thought was, if there are two similar pages at similar path in two different shared libraries, at runtime the page which was available first was displayed.

Finally the solution is to rename the pages and page def files simply to make the path different and everything was fine.


Thursday, February 11, 2016

Reset Sort and Filter Criteria

Issue: Clearing the values entered in QBE (Query by example) and Sort fields of a table


If the user enters a value in the QBE or filter and perform some kind of sort on fields above the header of the attribute columns the values are not cleared even after reset.  

It keeps the values and applies the Sort and filter criteria even after reset and search.


Solution:




The utility method below would clear out both the filter and Sort criteria applied by the user on click of reset.

The utility method takes the results table and the Iterator as the input and clears the sort and filter criteria applied by the user.

To call the method you have to write the custom query operation listener and check if the operation name is RESET.

public static void clearFilterCriteria(RichTable targetTable, String       iterator) {
targetTable.queueEvent(new SortEvent(targetTable,new                           ArrayList<SortCriterion>()));
SortCriteria[] sc = new SortCriteria[0];
        //Clears the Sort Criteria        ADFUtils.findIterator(iterator).applySortCriteria(sc);
FilterableQueryDescriptor queryDescriptor =            (FilterableQueryDescriptor)targetTable.getFilterModel();  
if (queryDescriptor != null && queryDescriptor.getFilterCriteria() != null) {           // Clears the Filter Criteria            queryDescriptor.getFilterCriteria().clear();}
}
}


Cascading LOV : Default Value

Issue: In Cascading LOV's if one of the child LOV's had single value then it should be selected by default as soon as the user selects the value in parent LOV


Solution: 

The trick is to access the ViewAccessor of the LOV, check the estimated row count and if it is 1 then get the value and set it to the attribute of the View object.

Creating RowImpl for the view object and in the getter of the attribute add the following code


    /**     * Gets the attribute value for the calculated attribute LocationId.
     * @return the LocationId
     */
    public Number getLocationId() {
        return this.getLocationsLOV1().getRowCount() == 1
                 ? ((DBSequence)this.getLocationsLOV1().first().getAttribute("LocationId")).getSequenceNumber()
                 : (Number)getAttributeInternal(LOCATIONID);
    }

Friday, October 3, 2014

Passing bind variable value from view criteria(af:query) to next page

Issue/Scenario:

 User performs search on Employee Name and if there is no record in the data base with that name then user would click on Create employee button which takes to create employee page and the employee name should be populated with the name, user entered in the search criteria.

Solution:

Create the view criteria on the view object and create the search form based on the view criteria.

Create java implementation class for the view object on which the View Criteria is defined and make sure you include the bind variable accessors


Select the get method of bind variable and make it available to the client or in other words expose it.


Drag and drop the getinFirstName method on to the task-flow as method activity which will give us the value in the bind variable which user enters while performing the search.

As the user needs to be redirected to Create Employee page and the first name should be populated,. Follow the steps below to achieve the before mentioned.

Open the getinFirstName method page definition file and create a Create Insert operation action binding

Select the getinFirstName method activity on the taskflow and change the value of the method property to managed bean method you just created.



Place the following code in the managed bean method.

    public void createEmployee() {

        OperationBinding op = ADFUtils.findOperation("getinFirstName");
        String name = (String)op.execute();
        JSFUtils.setExpressionValue("#{pageFlowScope.firstName}", name);
        op = ADFUtils.findOperation("CreateInsert");
        op.execute();
    }
 Once you get the bind variable value you can access it either from the page flow scope or you can populate it into the new inserted row.

I am using page flow scope variable to populate the first name in the create employee page.

Your task flow should look as the screen shot below

Monday, September 29, 2014

Creating EJB query with Criteria Builder


Just documenting it for future purposes or any one in need of help

import javax.persistence.EntityManager;
import javax.persistence.TemporalType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

public class SampleCriteriaBuilder {

EntityManager entityManager = null;
CriteriaBuilder criteriaBuilder;
List<Predicate> andPredicates = new ArrayList<Predicate>();
TypedQuery<YourDTOObjectRoot> query;

    public SampleCriteriaBuilder(EntityManager entityManager) {
        super();

        this.entityManager = entityManager;

        criteriaBuilder = this.entityManager.getCriteriaBuilder();
        criteriaQuery = criteriaBuilder.createQuery(YourDTOObject.class);

        yourDTOObjectRoot = criteriaQuery.from(yourDTOObject.class);

        childTable1Root = yourDTOObjectRoot.join("childTable1", JoinType.LEFT);
        childTable2Root = yourDTOObjectRoot.join("childTable2", JoinType.LEFT);
                           
    }
    // Like clause
       
         Predicate likePredicate =
          criteriaBuilder.like(childTable1Root.get("someAttribute"),
 "%" + value + "%");
         andPredicates.add(likePredicate);
       
        // In clause

           String commaSepValue = "one,two,three,four";
            javax.persistence.criteria.CriteriaBuilder.In<String> inClause =
                criteriaBuilder.in(yourDTOObjectRoot.<String>get("someAttribute"));

           List commaSepValueList = commaSepValue.split(",");
            for (String valueTaken : commaSepValueList) {
                inClause.value(valueTaken);
            }

            andPredicates.add(inClause);
        // Or Clause
       
            Predicate orClause =
                criteriaBuilder.or(criteriaBuilder.equal(childTable1Root.get("someProperty"), "someValue"), criteriaBuilder.like(childTable1Root.get("someProperty"),"otherValue"));           
               
            andPredicates.add(orClause);
           
        //Comparision between two dates
       
        Path timeStampPath = yourDTOObjectRoot.<Date>get("timestamp");

        ParameterExpression<Date> dateFromExp = criteriaBuilder.parameter(Date.class);
        ParameterExpression<Date> dateToExp = criteriaBuilder.parameter(Date.class);

        Predicate predicate_date = criteriaBuilder.between(timeStampPath, dateFromExp, dateToExp);
        andPredicates.add(predicate_date);
                Predicate[] predicates = (Predicate[])andPredicates.toArray(new Predicate[andPredicates.size()]);

        criteriaQuery.where(predicates);

        query = entityManager.createQuery(criteriaQuery);

        query.setParameter(dateFromExp, dateFrom, TemporalType.DATE);
        query.setParameter(dateToExp, dateTo, TemporalType.DATE);
}

Thursday, September 25, 2014

Ant script - Pre-compile JSPX files - ADF application

I happened to work on implementing the pre-compile jsps for our application and on doing a web search I came across the following blog

https://blogs.oracle.com/groundside/entry/appc_from_ant and it was spot on

and had to just re-use it.

I made the changes according to our application and run the ant task.

Started compiling jspx files but suddenly it fallover with the following error.

There are 1 nested errors:

The type javax.servlet.jsp.tagext.BodyTagSupport cannot be resolved. It is indirectly referenced from required .class files
The type javax.el.ValueExpression cannot be resolved. It is indirectly referenced from required .class files


For some reason it was not able to figure out BodyTagSupport class or may be it could not find the class at designated place.

I have changed the script to include weblogic.jar to the class path and it was all fine.


<?xml version="1.0" encoding="UTF-8" ?>

<project name="AppcTest" default="precompile" basedir=".">
  <description>Sample build file using Ant to call WLS APPC</description>
  <property name="wls_root" value="/oracle/fmwhome"/>
  <property name="wls_home" value="${wls_root}/wlserver_10.3"/>
  <property name="adf_lib_root"
                    value="${wls_root}/oracle_common/modules"/>
  <property name="java_home" value="/oracle/javahome"/>
  <property name="common_lib_root"
                    value="${wls_home}/common/deployable-libraries"/>

  <property name="ear_root"   value="${ear.root}"/>

  <path id="wls.classpath">
    <pathelement path="${wls_home}/server/lib/weblogic.jar"></pathelement>
  </path>
  <echo message="Setting path"></echo>
  <property name="project.class.path.property" refid="wls.classpath"/>
  <echo>PATH = "${project.class.path.property}"</echo>
  <taskdef name="wlappc" classpathref='wls.classpath'
                  classname="weblogic.ant.taskdefs.j2ee.Appc"/>
  <target name="precompile" description="Calls WLS APPC to pre-compile an EAR">
    <wlappc source="${ear_root}/deploy/ear-file-name.ear" verbose="true"
            classpath="${adf_lib_root}/oracle.adf.share_11.1.1  
                               /adfsharembean.jar:${wls_root}/wlserver_10.3/server  
                               /lib/weblogic.jar">

      <library file="${common_lib_root}/jstl-1.2.war"/>
      <library file="${common_lib_root}/jsf-1.2.war"/>
      <library file="${adf_lib_root}/oracle.adf.view_11.1.1
                               /adf.oracle.domain.webapp.war"/>
      <library file="${adf_lib_root}/oracle.adf.model_11.1.1
                               /adf.oracle.domain.ear"/>
      <library file="${wls_root}/Oracle_SOA1/soa/modules
                         /oracle.soa.workflow_11.1.1/oracle.soa.workflow.wc.jar"/>
      <library file="${wls_root}/Oracle_SOA1/soa/modules
            /oracle.soa.worklist.webapp_11.1.1/oracle.soa.worklist.webapp.war"/>
    </wlappc>
  </target>
</project>

Custom ADF application through BPM workspace - Null Pointer Exception - when performed action on the last worklist item in the workspace

Issue

   While working on a custom ADF application which is accessed through the BPM workspace whose taskflows are generated from human tasks encountered the issue as described below.
 
   Accessing the last item in the worklist and perform action which deletes the item from the worklist.
 
   If the action is performed as part of workspace inbox, everything works fine.
  
   Worklist throws a null pointer exception if the user double clicks and opens up worklist item in the separate window and submits any outcome.

   The popup window goes blank and throws up the NPE. Close the window and refresh the inbox, the worklist item is gone as expected but with the error. 

   Please find the error below.

Caused By: java.lang.NullPointerException
        at oracle.bpel.worklistapp.util.WorklistServiceUtil.isTaskFlow(WorklistServiceUtil.java:1152)
        at oracle.bpel.worklistapp.tasklist.beans.controller.TaskController.launchTaskDetails(TaskController.java:506)
        at oracle.bpel.worklistapp.tasklist.beans.controller.TaskController.launchExternalWindow(TaskController.java:745)
        at oracle.bpel.worklistapp.tasklist.beans.controller.TaskController.fetchNewTask(TaskController.java:767)

Solution

   Here I go thinking to solve the issue started looking at
    
      1. Method bindings - whether they are pointing to the correct method, iterator etc.,
      2. Anything unusual in Page Definition file.
   Nothing un usual in the JSPX, pagedef. So started looking at the human task itself from which the ADF taskflow is generated.    
      3. Suspected that there is no outcome of such which is being executed, but everything is fine :(
      
   Flushed out all the thoughts and started looking at ADF taskflow and found the issue with the control flows.

   So, here is the solution which is simple but took a while to figure out. 
          
    1. Go to the bounded taskflow and create control flow between jspx and taskFlowRefresh return activity.
    2. Make sure the outcome of the return activity is "done".
  

Thursday, July 19, 2012

DB Connections Accumulated while navigating through Webcenter pages

DB Connections Accumulated

Issue :

While navigating through the webcenter pages found a strange behavior around DB connections count.
Each time the user navigates to a page the DB connection count increased. The DB connections got accumulated and we had to restart the Spaces server every now and then.  The performance was degraded.

Solution:

While generating the top level menu in the page template hyperlink component was used.

When the user click on the hyperlink a URL gets generated along with the following parameter contains the state of your session which is appended to the url

adf.ctrl-state%3X232w0en123_45

Each time the hyperlink is accessed ADF regenerates a new parameter(adf.ctrl-state%3Z3422uu0en678_98) and complete session state, so it's essentially creates a new session that will use resources.

As a result each time the user click on hyperlink the number of connections increased by one every time.

Use of an ADF Component instead of hyperlink component that doesn't show the same problem.  The current page url would have the same parameters attached irrespective of several navigation across pages and would use the same DB connection.