Tuesday, July 23, 2019

Showing Parameters passed in the URL in a page – Oracle ADF

In ADF Application we can read the parameters passed in the URL and display them as an output text using a simple EL (Expression language).
#{param.paramName}

Sample Jspx page:
1
Page in browser:
2If your requirement is to show the URL passed in parameter data in the input text field and if there is no parameter data passed then show it as an input text field, then you can use below given EL which is having the ternary condition.

<af:inputText value=”#{param.dept eq null? bindings.DepartmentId.inputValue: param.dept}” />

Browser output when URL: 
3.PNG
Browser output when URL: 
4.PNG

This post is intended to show how the requirement can be fulfilled with the help of EL.

Collecting Changed Row Keys in ADF BC DoDML Method


If you ever had a question - how to collect information about all changed rows in the transaction, I will provide an answer in this post. As you perhaps already know, doDML method from Entity Implementation class is invoked per each changed row. This means our task is to collect Primary Keys for all changed rows and later access this collection from another method, to be able to process collected keys (log them, call PL/SQL, etc.).

Sample application - DoDMLExceptionProcessingApp_v2.zip, overrides doDML method and collects all changed rows for Employees EO. In real use case, this should be more generic, if you want to apply similar logic for different EO's, however you should follow the same concept as described here. In doDML I collect information about Primary Key programmatically, getting key value and saving it in collection. Later this collection is stored in ADF BC session user data. There is no need to passivate collection with changed rows Primary Keys, as we are going to access it in the same request from afterCommit method on VO level - there will be no passivation in between:


I'm using a trick to get information about Entity primary key programmatically. There is a method called getPrimaryKeys in Entity Definition class, but this method is marked as protected, so I can't access it from custom code. However, I can implement my own Entity Definition class, override getPrimaryKeys protected method inside custom public method - in such way, I will make it available for custom methods:


doDML is invoked for every changed row, we need a method to be called at the end, to access collected info. Such method could be - afterCommit in View Object Implementation. This method is called after all rows are processed in doDML. I'm getting information about Primary Key and accessing ADF BC user data variable, where Primary Keys for all changed rows are stored. In this example, I'm simply printing out keys for all changed rows:


Here we can see, how it works. Change data in multiple rows and press Save:


Information about Primary Key name and values for every row containing changes is printed out:


We could use Primary Key values to access changed rows, process attributes we are interested in and call PL/SQL if required, using attribute values as parameters.

Monday, July 22, 2019

How many rows Modified/Added in ADF Table

How many rows Modified/Added in ADF Table

I was reading through OTN Discussion Forums where I found one topic "How many rows were Modified/Added in ADF Table by the user". Jobinesh has written article on "Displaying Transaction Log When User Commits a Transaction" which explains how to get the entity status, above example overrides EntityImpl::doDML(int operation, TransactionEvent e) method to track the status of entities.

I was trying to get Modified/Added rows in EJB DataControl but above suggested solution can't be implemented, because application module in not supported in EJB. So in this article I'm trying to get the entity status in backing bean using BC4J, in my next article I will try to explain on how to achieve the same scenario using EJB.

Results page looks like below.


You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.2.0 + HR Schema]

Implementation Steps:

Create Fusion Web Application with business components from tables based Employees table, open Employees.xml and select Java tab. Generate EmployeesImpl and add the below code in create method to generate sequence number for employee id using SequenceImpl class.
/**
 * Add attribute defaulting logic in this method.
 * @param attributeList list of attribute names/values to initialize the row
 */
protected void create(AttributeList attributeList) {
 super.create(attributeList);
 SequenceImpl seq = new SequenceImpl("EMPLOYEES_SEQ", getDBTransaction());
 Number seqNextval = seq.getSequenceNumber();
 setEmployeeId(seqNextval);
}
Open the EmployeesView and select Java tab, generate EmployeesViewImpl class.

In ViewController project, create index.jspx page and backingbean as "IndexBean" with scope as "ViewScope". Open the IndexBean and copy the below method code.
private RichTable empTable;
private List selectedEmpArray = new ArrayList();
private int modifiedRows = 0;
private int newRows = 0;

public IndexBean() {
}

public void setEmpTable(RichTable empTable) {
 this.empTable = empTable;
}

public RichTable getEmpTable() {
 return empTable;
}

public void setModifiedRows(int modifiedRows) {
 this.modifiedRows = modifiedRows;
}

public int getModifiedRows() {
 return modifiedRows;
}

public void setNewRows(int newRows) {
 this.newRows = newRows;
}

public int getNewRows() {
 return newRows;
}

/**
 * Get the selected rowKey
 * Add the rowKey to selectedEmpArray arrayList
 * @param selectionEvent
 */
public void empSelectionEvent(SelectionEvent selectionEvent) {
 RowKeySet empRKS = selectionEvent.getAddedSet();
 if (empRKS.size() > 0) {
  Iterator empRKSIterator = empRKS.iterator();
  while (empRKSIterator.hasNext()) {
   Key key = (Key)((List)empRKSIterator.next()).get(0);
                        //Add the key if not existed in selectedEmpArray
   if (!selectedEmpArray.contains(key)) {
    selectedEmpArray.add(key);
   }
  }
 }
}

public BindingContainer getBindings() {
 return BindingContext.getCurrent().getCurrentBindingsEntry();
}

/**
 * While loop the selectedEmpArray
 * Get the entity status for the rowKeys
 * @param actionEvent
 */
public void fetchModifiedRows(ActionEvent actionEvent) {
 if (selectedEmpArray.size() > 0) {
  //Resetting the row counts
  this.setModifiedRows(0);
  this.setNewRows(0);

  DCBindingContainer dcBindings = (DCBindingContainer)getBindings();
  DCIteratorBinding EmpsDCIterBinding = dcBindings.findIteratorBinding("EmployeesView1Iterator");
  RowSetIterator EmpsRSIter = EmpsDCIterBinding.getRowSetIterator();
  ViewObject vo = EmpsDCIterBinding.getViewObject();

  Iterator selectedEmpsIter = selectedEmpArray.iterator();
  while (selectedEmpsIter.hasNext()) {
   Row currentRow = EmpsRSIter.getRow((Key)selectedEmpsIter.next());
   EmpsRSIter.setCurrentRow(currentRow);

   ViewRowImpl myRow = (ViewRowImpl)vo.getCurrentRow();
   EntityImpl entityImpl = (EntityImpl)myRow.getEntity(0);
   if (EntityImpl.STATUS_MODIFIED == entityImpl.getEntityState()) {
    this.setModifiedRows((this.getModifiedRows() + 1));
   } else if (EntityImpl.STATUS_NEW == entityImpl.getEntityState()) {
    this.setNewRows((this.getNewRows() + 1));
   }
  }
 }
 //Commit the transaction
 commitAction();
}

public String commitAction() {
 BindingContainer bindings = getBindings();
 OperationBinding operationBinding = bindings.getOperationBinding("Commit");
 Object result = operationBinding.execute();
 if (!operationBinding.getErrors().isEmpty()) {
  return null;
 }
 return null;
}

/**
 * CreateInsert new row and get rowKey for the added row
 * Add the rowKey to the selectedEmpArray arrayList
 * @param actionEvent
 */
public void createNewRow(ActionEvent actionEvent) {
 BindingContainer bindings = getBindings();
 OperationBinding oper = bindings.getOperationBinding("CreateInsert");
 oper.execute();

 DCBindingContainer dcBindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
 DCIteratorBinding EmpsIter = dcBindings.findIteratorBinding("EmployeesView1Iterator");
 EmployeesViewImpl eImpl = (EmployeesViewImpl)EmpsIter.getViewObject();
        //Add the key if not existed in selectedEmpArray
 if (!selectedEmpArray.contains(eImpl.getCurrentRow().getKey())) {
  selectedEmpArray.add(eImpl.getCurrentRow().getKey());
 }
}
Note:- Here createInsert is model driven component, when user clicks on the Create button the selectionListener will not be executed for the first time. So in the above createNewRow method,  the rowKey value will be added to selectedEmpArray.

Open index.jspx page.
  • From datacontrol palette drag and drop EmployeesView1->Table as ADF Table with rowSelection as multiple.
  • Surround the table with panel collection and add toolbar in that.
  • Bind the empolyees table as binding="#{viewScope.IndexBean.empTable}"
  • Set the SelectionListener as "#{viewScope.IndexBean.empSelectionEvent}"
  • Go to Bindings tab and Create Action Binding, Data Collection as EmployeesView1 and Operation as CreateInsert.
  • From component palette drop af:commandButton and set actionListener as "#{viewScope.IndexBean.createNewRow}".
  • Go to Bindings tab and Create Action Binding, Data Collection as AppModuleDataControl and Operation as Commit.
  • From component palette drop af:commandButton and set actionListener as #{viewScope.IndexBean.fetchModifiedRows}, disabled as "#{!bindings.Commit.enabled}", partialSubmit as "true".
  • Add af:outputLabel and value as "No of Rows Modified -  #{viewScope.IndexBean.modifiedRows}", partialTriggers to commit button.
  • Add af:outputLabel and value as "No of Rows Newly added - #{viewScope.IndexBean.newRows}",  partialTriggers to commit button.

Thursday, July 4, 2019

ADF JSF : ADFc: Scope object serialization failed (object not serializable) and Managed Bean , Backing Bean

When I was testing I noticed on web logic EM logs that there is constant exception coming every second.


Download Code from Here , After Download go to TestSer.java and remove Serializable and run code you will notice below exception and then implement serializable this exception will be gone.

image

Let me demo you precisely why this happened.

Backing Bean

This is actually BackingBean which has one to one relationship with each and every component in java file.

image

It has getter and setter for each component on GUI.

image

Here is sample GUI and if you double click button it will allow you to create action inside this backing bean.

image

Also, before running please don’t forget to set following java option.

image

org.apache.myfaces.trinidad.CHECK_STATE_SERIALIZATION – This check is disabled by default. It checks no unserializable state content on session attributes is detected
After running application when I clicked button , it simply printed button called without any exception’

image

Managed Bean : Practice in ADF

Generally In ADF Development developer will not create backing bean for each and every JSF , JSFF. he will instead create one Managed Bean for whole TaskFlow consisting of multiple JSFF. Each JSFF page will call that managed bean to perform it operation.

image

So I created new Managed Bean (TestSer.java) and bind it to second button then ran the application without Serializable implemented in TestSer bean it was throwing above exception from both button.

but when I implemented Serializable in TestSer.java then it stopped throwing above exception from both button.

Note:- I did not implements Serializable in backingBean TestSerialization.java.

image

So please make sure you implements Serializable in this type of Managed bean॥

When you are designing an application to run in a clustered environment, you must:
Ensure that all managed beans with a life span longer than one request are serializable (that is, they implement the java.io.Serializable interface). Specifically, beans stored in session scope, page flow scope, and view scope need to be serializable.

ADF : Page loads - Call refreshRegion() when JSFF page loads

ADF : Page loads - Call refreshRegion() when JSFF page loads



ADF : ADF Table not displaying rows 1st time.


ADF : ADF Table not displaying rows 1st time.


If we are using <af:quickQuery component against VO (ADF table), always we should mark "Query Automatically" checked, other wise rows will not be displayed 1st time when we land to the page.

Best ADF Blogs

ADF: ADF Table clear Filter





    public void resetFieldTableFilter()
        {
        try {
            FilterableQueryDescriptor queryDescriptor =
                (FilterableQueryDescriptor)this.getFieldTable().getFilterModel();
            if (queryDescriptor != null &&
                queryDescriptor.getFilterCriteria() != null) {
                queryDescriptor.getFilterCriteria().clear();
                this.getFieldTable().queueEvent(new QueryEvent(this.getFieldTable(),
                                                               queryDescriptor));
            }
        } catch (Exception e) {
            if (AppsLogger.isEnabled(AppsLogger.SEVERE)) {
                AppsLogger.write(this,
                                 "Exception in  resetFieldTableFilter :" +
                                 e.getMessage() + " ", AppsLogger.SEVERE);
            }
        }
        }

ADF : Serializable

ADF : Serializable


All the managed beans should be serializable because the container may occassionally serialize and passivate the beans or send it over the network. This occurs in situations 
such as heavy load (our case) or when clustering is enabled.

Another tip:

- The managed beans with pageFlow or session scope are required to be serialized while backingBean or request scope are not required to be serialized.

- The ADF/JSF Rich UI components are not serializable and hence they should not be present in pageFlow scope managed beans.

Response: Your pageFlowScope bean should implements Serializable.


Eg:


Possibility 1:



Possibility 2:







Possibility 3:








Possibility 4:


Report


By setting this in java option we will get to know the issues in diagnostic or em logs.

-Dorg.apache.myfaces.trinidad.CHECK_STATE_SERIALIZATION=all

check : http://hasamali.blogspot.in/2011/09/adf-jsf-adfc-scope-object-serialization.html



About - serialVersionUID


The serialVersionUID is used as a version control in a Serializable class. If you do not explicitly declare a serialVersionUID, JVM will do it for you automatically, based on various aspects of your Serializable class

Check - https://www.mkyong.com/java-best-practices/understand-the-serialversionuid/





How Server does Serialization and Deserialization

A simple way to write / serialize the UserBean object into a file – “c:\\UserBean.ser”.


FileOutputStream fout = new FileOutputStream("c:\\UserBean.ser");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(UserBean Obj);




A simple way to read / deserialize the UserBean object from file – “c:\\UserBean.ser”.



   FileInputStream fin = new FileInputStream("c:\\UserBean.ser");
   ObjectInputStream ois = new ObjectInputStream(fin);
   UserBean = (UserBean) ois.readObject();

Wednesday, July 3, 2019

Programmatically showing the Popup in ADF

Requirment – To display popup in adf programmatic.

You have to display the popup on click of some button. Drag drop the af:popup in the page and bind the popup in the managed bean like screenshot
On the button , write a method on the action event.
public void ShowPopup(ActionEvent actionEvent) {
          RichPopup.PopupHints hints = new RichPopup.PopupHints();
          this.getPopUp().show(hints);
 
 }
If you want to hide the popup..you can write like this
public void HidePopup(ActionEvent actionEvent) {
           RichPopup.PopupHints hints = new RichPopup.PopupHints();
           this.getPopUp().hide();
 
  }