Tuesday, August 31, 2010

<af:progressIndicator> example

A simple demo application that uses <af:progressIndicator> is attached here. Please refer the tag documentation to learn more about <af:progressIndicator> component.

[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]

Friday, August 20, 2010

A composite ViewObject based on multiple data sources

Sometimes you may need to display data from different data sources on a single row. Say for example, part of the row from database and a couple of attributes from a third party data source. ADF BC let you to customize the ViewObject to compose data from different sources by overriding a couple of 'life cycle' methods. Below given sample code illustrates the same. Here, you can see that EmployeesViewObject tries to get value for 'LocationDetails'(transient attribute on Employee ViewObject) from a third party data source exposed through some custom APIs.


/**
* executeQueryForCollection - overridden for custom java data source support.
*/
protected void executeQueryForCollection(Object qc, Object[] params,
                     int noUserParams) {
  thirdPartyDataSource.filterOutValues(params);
  super.executeQueryForCollection(qc, params, noUserParams);
}

/**
* createRowFromResultSet - overridden for custom java data source support.
*/
protected ViewRowImpl createRowFromResultSet(Object qc,
                     ResultSet resultSet) {
  EmployeesViewRowImpl rowImpl = (EmployeesViewRowImpl)super.createRowFromResultSet(qc, resultSet);
  rowImpl.populateAttribute(EmployeesViewRowImpl.LOCATIONDETAILS, 
  thirdPartyDataSource.getValueForAttribute
    (EmployeesViewRowImpl.AttributesEnum.LocationDetails.toString(), 
        rowImpl.getKey().getAttributeValues()));
  return rowImpl;
}

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]

Tuesday, August 17, 2010

Customizing the order of posting changes to database

There are some use cases where you may need to control the order of posting changes to database( in other words, control the order in which the entity objects in the 'pending changes list' are processed ). This situation may arise when you want to delete a specific record and modify another record with deleted records attribute values for which 'uniqueness constraint' is defined at database level. Please note that by default, when you commit the transaction the entity objects in the pending changes list are processed in chronological order, in other words, the order in which the entities were added to the list( Read more... ).
All goes well when user opts to delete a record first, and as next step modify an existing records with deleted records attribute values. In this case deleted record gets added to the pending changes list first, followed by the modified one. There are some interesting scenarios where you may need to outsmart the business users to make it work. Please see the below shown scenario, where a business user updates employees records in a specific sequence.

1. User modifies name field of an employee record with id=10 .
2. He/She selects employee record with id=20 and delete the same .
3. Navigate back to employee record id=10 and amend the email column with the email of the deleted record (note : email column is having 'unique constraint' at db level)
4. Tries to commit the changes. This operation throws 'uniqueness constraint' violation error as the transaction manager tries to perform the update operation on table before delete.

A bit about the implementation

A possible solution for the use case is to control the post order of entities, i.e. post the deleted entities first, followed by the new/modified entities. You can customize the post changes by adding your own customized oracle.jbo.server.DBTransactionImpl class. Idea is to reorder the TransactionPostListenersList(pending changes list) to keep the deleted entities at the beginning.

To hook your version of DBTransactionImpl, you may need to create DatabaseTransactionFactory which in turn should return the customized DBTransactionImpl class. As last step, modify the bc4j.xcfg file to enable the ApplicationModule to use the custom DatabaseTransactionFactory. Please refer this link - Creating and Using a Custom DBTransaction Implementation - to learn more on this topic.

<?xml version = '1.0' encoding = 'UTF-8'?>
<BC4JConfig version="11.1" xmlns="http://xmlns.oracle.com/bc4j/configuration">
   <AppModuleConfigBag ApplicationName="model.AppModule">
      <AppModuleConfig name="AppModuleLocal" ApplicationName="model.AppModule" 
          TransactionFactory="fmwk.extension.CustomDatabaseTransactionFactory" 
          DeployPlatform="LOCAL" JDBCName="HRConn" jbo.project="model.Model">
         <Security AppModuleJndiName="model.AppModule"/>
      </AppModuleConfig>
   .........
</BC4JConfig>

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]

Thursday, August 12, 2010

Refresh the parent view when a taskflow displayed in a popup returns

This post discusses an interesting use case on refreshing the parent view when an in-line popup taskflow returns. There are two taskflows, both work with separate transaction contexts(Transaction attribute is set as new-transaction). Second taskflow is invoked from the first one as a dialog. The requirement here is to refresh the 'executables' of calling page(from first taskflow) when the second taskflow returns. This scenario usually arises when the second task flow updates tables used by the first one from a different transaction context.

To learn more on taskflow, please refer Part III Creating ADF Task Flows in Fusion Middleware Fusion Developer's Guide for Oracle ADF.

Cool, now back to the use case. One possible solution for the above scenario is to define a returnListener for secondary window on the command button (which invokes second taskflow as dialog) and add the custom logic to refresh the underlying IteratorBindings used by the parent page. Last step is to manually refresh the parent view by adding it as PartialTarget - RequestContext.getCurrentInstance().addPartialTarget(returnEvent.getComponent().getParent().getParent());
That's it, job is done. I'm copying the relevant code snippet below for your reference.
<af:commandMenuItem text="Create" id="cmi1" action="create"
useWindow="true"
windowEmbedStyle="inlineDocument"
windowModalityType="applicationModal"
returnListener="#{viewScope.RefreshBean.dialogReturnListener}"
windowHeight="250" windowWidth="500"/>
public void dialogReturnListener(ReturnEvent returnEvent) {
  BindingContext bc = BindingContext.getCurrent();
  DCBindingContainer dcb =
    (DCBindingContainer)bc.getCurrentBindingsEntry();
  DCIteratorBinding iter =
    dcb.findIteratorBinding("DepartmentsView1Iterator");
  iter.executeQuery();
  RequestContext.getCurrentInstance().addPartialTarget(returnEvent.getComponent().getParent().getParent());

}

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]

How to run this sample?

Run the main.jspx. This page contains 'outer-task-flow-definition' which displays Departments details on a table. Select the 'create' menu item from the toolbar, which opens up 'inner-task-flow-definition' in a popup. Key in the new department details and click on Save. This action closes the popup and then refreshes the parent view to display new record.


Learn More ...

There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html

Tuesday, August 10, 2010

XML for Queried Data

ADF Business Components helps you to transform queried data into xml format. Interestingly, you can manipulate this xml content without much effort, and the same can be posted back to database as well. Please refer this topic 39.7 Reading and Writing XML in Fusion Middleware Fusion Developer's Guide to learn more.

I'm attaching a simple demo application illustrating the usage of ViewObject::readXML(...) and ViewObject::writeXML(...) APIs.
You can download the sample workspace from here. Please see CRUDXMLTestClient.java file in the sample project.
[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]

PS: Please note that ViewObject.readXML() will create new row, if the row that you supplied in the xml has not been retrieved by calling findByKey(). New row is inserted into the view object's rowset. Its attributes are populated using the values in any attribute element children of the current row element in the XML.

If the primary key for the new row(EntityObject) is populated using DB Sequence, please remove that attribute from the xml. ADF run time will take care the rest if you have proper implementation in your XXXEntityObjectImpl class to use DB Sequence.

Friday, August 6, 2010

Posting a JSF page to Servlet

There are some use cases which requires posting data to a (legacy) Servlet for further processing and on success, redirect to a JSF page. This example illustrates a possible solution for similar scenarios - posting a JSF page to a Servlet. Basic idea is to invoke a custom javascript method on click of the button and submit the form to a customized 'action' target(Servlet).
<af:commandButton text="Post Me" id="cb1">
  <af:clientListener type="action" method="customPostHandler"/>
</af:commandButton>

<af:resource type="javascript">
  function customPostHandler(event) {
      var form = document.forms[0];
      form.action = '/some-context-root/sampleservlet';
      form.submit();
      event.cancel();
  }
</af:resource>
You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS2]

How to run this sample?

Run the login.jspx page. This page is pre-populated with values for user name and password fields, leave the default values as is. Click on 'Post Me' button. This in turn posts data to 'SampleServlet' which processes the posted data, and on success, request is getting redirected to welcome.jspx