Tuesday, December 28, 2010

ADF UI - Implementing Date Effective Search with Example

After learning how to create date-effective objects (i.e., Creating Date-Effective EO, Creating Date-Effective Associations and VOs), now we'll see how to implement date-effective search.

Sample Use Case:
Please go through my previous post to see the sample example use cases of performing date-effective operations on 'Job' object. So, here the requirement is to search for a job effective as of the given date. Sample application illustrating this example can be downloaded from here. Before running the example, you need to create the required tables in DB. The sql script for these table can be downloaded from here.

Implementation Steps:
1. Create the date-effective EO (JobEO) and date-effective VO (JobVO). Marking the JobVO will create a new transient attribute called SysEffectiveDate in the VO attributes.

2. Create a view criteria 'JobSearch' and add the required attributes as query criteria items on which you want to perform the search. As a best practice, use bind variables for all the view criteria items(attributes).

3. In addition to those attributes, add SysEffectiveDate in the query attributes and bind it to the bind variable SysEffectiveDateBindVar of type Date(if this bind variable is not already exist, create a new bind variable with same name and associate it to SysEffectiveDate). Here, the bind variable name that binds SysEffectiveDate should be SysEffectiveDateBindVar as this is the bind variable name generated at runtime by ADF for SysEffectiveDate. Otherwise, it'll throw run time exception.

4. Now, you're done with model part of defining view criteria with SysEffectiveDate. Now, implement search and search results in a jsff with this view criteria.

5. To test the functionality, create multiple job records with different date-effective updates and try to search for a required job records specifying the Effective Date in the search criteria. You'll get the job records which match the query criteria as of the given effective date. Here are the sample screen shots.

6. If the effective date (SysEffectiveDate) is not provided, it'll return the rows effective as of today (i.e.,the system date on which search is made). Screen shot below.


Sunday, December 26, 2010

ADF Model: Creating Date Effective Association and Date Effective VO

To learn the basics of date-effectivity in ADF, please go through my post Learning basics of Date Effectivity in ADF. To learn how to create date-effective EO, please go through my post Creating Date Effective EO.

Creating Date Effective Association:
To have the basic idea of association between EOs, please go through my post ADF Model: Creating Entity Association. But, by default the association created is not date-effective. But, if you're creating association between two EOs in which at least on of them is effective-dated, then you should mark the association as 'Effective Dated'. To make the association date-effective,

1. Open Association -> Goto 'Relationship' tab -> Behavior -> Check 'Effective Dated Association' checkbox.
Marking the association 'Effective Dated Association' will take effective date into consideration while searching, inserting and updating the records.

Creating Date Effective VO:
Creating date effective VO is same as creating normal VO. In addition, we need to

1. Mark the VO as date-effective by setting EffectiveDated='true' for the VO. You can find this property in 'General' tab property inspector.

Specifying the above property for the VO will generate a new transient attribute called SysEffectiveDate in the VO.

2.Optional: Change the data type of SysEffectiveDate attribute to 'java.sql.Date' from 'oracle.jbo.domain.Number'. We'll often find it easier with native Java sql data types instead of using Oracle's jbo datatypes. It is recommended to use java native sql type(java.sql.Date) for all date type attributes in the EO.

Marking the VO effective dated, will support date-effective updates for a single record.

Learning basics of Date Effectivity in ADF

This post explains the basics of date-effectivity which include mainly the basic date-effective operations like Date 'Effective Search', 'Date Effective Create', 'Date Effective Update' and 'Date Effective Delete'. But, it'll be easier to explain the concepts with examples.

So, here for example, I'm taking the simple example of HR admin, who can search/create/update/correct jobs. Let us assume, each job has a name, code and other attributes like job level, if the job requires medical checkup required, minimum salary, maximum salary, etc. What makes the job is date effective is that the attributes of job may change over the time, but still we need to be able to search the jobs based on the attributes that were applicable previously or that will be applicable in future.

For instance, let us take a job with Name 'Java Associate' which was created on 01-01-2000. When the job was created, the minimum salary for the job (minSal) was 10000 and maximum salary (maxSal) was 15000. But, on 01-01-2005, the job was revised and the management decided to move their technology to ADF and changed the job name to 'ADF Associate'.On 01-01-2010, the same job was revised and salary ranges were updated to minSal 25000 and maxSal 40000. Again, the management decided to change all Associate jobs to Developer Jobs from 01-01-2012 onwards (i.e., the job name will be changed from 'ADF Associate' to 'ADF Developer') etc.,

Here, the requirement is that if the user knows the name of the job applicable in 2000, he should be able to search the job as of that date. Similarly, if the user wants to search as of the current date or future dates, he should be able to search as well. That means we shouldn't simply update the existing values of the attributes as it will update the existing values and the previous values would be lost! We need to keep different versions of the attributes for the same job. So, how will it be possible as to have the multiple records with same JobId? Here comes EffectiveStartDate and EffectiveEndDate. Actually, we need to have a composite key based on JobId, EffectiveStartDate and EffectiveEndDate(i.e., the combination of these 3 attributes should be unique).

So, the data in the above requirement can be shown in table as follows. Changed attributes for each date-effective update are highlighted in yellow.

If you see the above table, you'll notice that for any change in the Job attribute, we have new row with the corresponding EffectiveStartDate and EffectiveEndDate and there are no gaps in between. i.e., for any given date, only one record is applicable among multiple date-effective rows of a single Job record.

Now we'll see what date effectivity means in ADF for different operations on the records.
Date Effective Search:
For example, if we want to find the jobs whose name starts with 'ADF%' as of date 01-01-2006. Or, we want to find out the jobs which will be applicable after 01-01-2012. Or, we want to find the minSal and maxSal for a given job as of 01-01-2007. Here, the results would change changing the Effective Dates as each job would have different values for the same attribute for different effective dates. Date-effective search will make all these possible. Date-effective search is explained with an example here.

Date Effective Create:
For example, we want to create a job that will be applicable in future say from 01-01-2013. Or, I want to create record which should be applicable from the past say 12-12-1900. Or, I want to create a new job which should be effective from today. Date-effective create makes all of these possible.

Date Effective Update:
For example, we want to insert a new date-effective record for the job to represent a change in one of the attributes of the job. Say, I want to update the maxSal of the job with jobId 1001 to 20000 from 01-01-2008. This will insert a new record for the same job with EffectiveStartDate 01-01-2008 with maxSal 20000. Different date-effective update modes and the corresponding behavior has been explained here.

Date Effective Correct:
For example, I want to correct or change one or more of the attributes of one of the date-effective rows of a single job record. Date Effective Correct operation just corrects the existing data. It won't insert any new date-effective rows. You can find the example of DE correction mode here.

Date Effective Delete:
For example, we want to delete a single date-effective record out of multiple date-effective records of a job. For instance, we want to delete the job record [1001, 01-01-2005, 31-12-2009]. If the record is non-date effective, then deleting the row means deleting the entire record as there won't be multiple rows. But, in case of date-effective objects, if you want to delete entire record, you need to delete all date-effective rows of that record if any.

Now, you understand the basics of date-effectivity in ADF. If you need any clarification, please leave a comment.

Thursday, December 23, 2010

ADF Model: Creating Date Effective EO

Date-effectivity is an excellent feature available in Jdeveloper 11g. To learn the basics of date-effectivity in ADF, please go through my post Learning basic of Date Effectivity in ADF. With Jdev 11g, we can create date-effective objects and do date-effective operations using simple API calls. Before going into all those details, the first requirement would be creating Date-Effective EO.

The first requirement to create a DE-EO based on a table, the table should have two date columns to represent Effective Start Date(ESD) and Effecitve End Date(EED) of the record and these columns should be marked as primary keys along with id column. In other words, we need to define a composite key based on the id column and ESD and EED columns.

Creating Date Effective EO is same as creating normal EO. In addition, we need to do the following steps to make it date-effective.
1. Mark the EO as Date Effective by specifying the attribute Effective Date Type = 'EffectiveDated'. You can find this property in 'General' tab property inspector.

This will generate a new transient attributte called 'SysEffectiveDate' in the EO. Please find the screenshot below:

2. We need to specify which columns represent effective-date columns by checking the Check 'Effective Date' check box and selecting 'Start' and 'End' radio buttons for the effective-date columns which represent Effective Start Date and Effective End Date. Find the screen shots below:

3. Optional: Change the data type of SysEffectiveDate attribute to 'java.sql.Date' from 'oracle.jbo.domain.Number'. We'll often find it easier with native Java sql data types instead of using Oracle's jbo datatypes. It is recommended to use java native sql type(java.sql.Date) for all date type attributes in the EO.

That's it. Now, your EO is date-effective and supports date-effective operations on it's rows.

Wednesday, December 22, 2010

ADF Model: Getting attribute values from parent VO to child VO and vice versa using view link accessors

In this post, let us see how to access parent VO attributes from child VO and child VO attributes from parent VO using view link. To have the basic idea about view links and how to create them, you can go through my blog post 'ADF Model: Creating View Link'.

Example Use Case:
For example we have two VOs DeptVO and EmpVO and both are linked via foreign key 'DeptId' using the view link EmpVOToDeptVO. Here, this relationship depicts the parent-child relationship using the foreign key DeptId. In other words, for a given current EmpVO(child) row, I need to know the DeptName from DeptVO(parent). Similarly, for a given current DeptVO(parent) row, I need to know all the empVO(child) rows. Sample application demonstrating this example can be downloaded from here.

Implementation Steps:
1. Create EmpVO and DeptVO and generate RowImpl classes for both of these two VOs.

2. Now, create a new view link say DeptVOToEmpVO between these two VOs via foreign key DeptId.

3. In the view link definition, select options to generate accessors in both source and destination VOs. i.e., in DeptVO and EmpVO.

4. Checking the above options will generate accessor methods in EmpVORowImpl and DeptVORowImpl. The accessor's return type in each VO is based on the type of relationship between the VOs. In other words, as the relationship between Dept and Emp is 1-to-many, the accessor in DeptVORowImpl will return multiple Emp rows(i.e, the return type of the accessor will be RowIterator). And, the accessor in EmpVORowImpl will return a single row (as an employee can be in only one dept).

If you observe the source of EmpVO and DeptVO, you can also see that a tag is added in each of these VOs for the viewLinkAccessor.

5. Now, you can use these accessors to get reference EmpVO from  DeptVO and vice versa. You can also get attribute values from the same. Sample codes below:

Sample method in EmpVORowImpl to get the dept name.
public String getDeptNameViaViewLink() { //Getting reference to deptVO row using the view link accessor getDeptVO1() Row deptRow = this.getDeptVO1(); //Getting the attribute 'Dname' value from the deptRow. return (String)deptRow.getAttribute("Dname"); }

Sample method in DeptVORowImpl to get the list of employees in the dept.
public List getEmpNamesViaViewLink() { //Getting reference to empVO row using the view link accessor getEmpVO() RowIterator empRowIterator = this.getEmpVO(); //Creating an empty List to store all emp names List empNames = new ArrayList(); //iterating through all employee rows while(empRowIterator.hasNext()){ //getting emp row one by one from the iterator Row empRow = empRowIterator.next(); //adding emp name to the empNames list empNames.add(empRow.getAttribute("Ename")); } //returning all empNames corresponding to the current dept return empNames; }

How to call/use these view link accessor methods in AMImpl methods?
This should be now pretty straightforward. Here is the sample AMImpl method which prints emp names in each dept. The code is self-explanatory.
public void sampleMethod() { //getting reference to deptVO ViewObjectImpl deptVO = this.getDeptVO(); //setting range size to -1 to get all dept rows deptVO.setRangeSize(-1); //getting all dept rows Row[] deptRows = deptVO.getAllRowsInRange(); //iterating through all dept rows for (int i = 0; i < deptRows.length; i++) { //getting reference to each dept row. Note that we're type casting the VO reference type to DeptVORowImpl. DeptVORowImpl deptRow = (DeptVORowImpl)deptRows[i]; //printing dept name System.out.println("Employees in dept: " + deptRow.getAttribute("Dname")); //For each dept row, getting reference to empVO which contains all employees corresponding to current dept RowIterator empRows = deptRow.getEmpVO(); //iterating each emp row while (empRows.hasNext()) { Row empRow = empRows.next(); //printing emp name from each row System.out.println(empRow.getAttribute("Ename")); } } }

Here is the sample output in console on running the above AMImpl method.

That's it. Now, you got the idea how to use view link accessors to get the values of child attributes from parent and vice versa. Enjoy!

Thursday, November 25, 2010

ADF Model: Executing view accessor programatically

In this post, I'll show how to execute a VO(or it's view criteria) added as a view accessor in another VO.

Sample Use case:
For example we have two VOs DeptVO(based on only DeptEO) and EmpDeptVO(based on empEO and DeptEO) and the DeptVO is added a view accessor in EmpDeptVO and we need to programmatically execute this view accessor to get the Deptno for the passed Dname (assuming it DeptVO has a view criteria that takes Dname as a parameter or bind variable) and set the DetpNo for the newly created row in EmpDeptVO. You can download the sample application from here.

Implementation Steps:
1. Create DeptVO based on DeptEO and create a view criteria "findByDeptName" that queries based on the bind variable 'Bind_Dname'.

2. Create EmpDeptVO and add the DeptVO as view accessor (DeptVA) and select the view criteria "findByDeptName" in the VA definition.

3. Generate RowImpl class for EmpDeptVO. The generated class name will be EmpDeptVORowImpl.

4. Now, write a method say "getDeptIdFromViewAccessor" in EmpDeptVORowImpl that takes 'Dname' as parameter that executes the view accessor DeptVA and returns the DeptId for the passed 'Dname'. Code below:
public Object getDeptIdFromViewAccessor(String deptName) { //here getDeptVA is the getter for the view accessor 'DeptVA' in EmpDeptVO RowSet rowSet = this.getDeptVA(); //setting the range size to -1 to get all the rows rowSet.setRangeSize(-1); //passing the value for bind parameter for the view accessor rowSet.setNamedWhereClauseParam("Bind_Dname", deptName); //executing the view accessor rowSet.executeQuery(); //storing the first row in the row set in deptRow (there can be multiple rows in the row set based on the criteria) Row deptRow = rowSet.first(); //if the dpetRow is not null, returning the Deptno return (deptRow != null) ? deptRow.getAttribute("Deptno") : null; }

5. Call the above EmpDeptVORowImpl method in AmImpl's method say "testExecuteViewAccessor" passing the Dname for which the DeptId is required. Now, set this deptId to the newly created EmpDeptVO row in AMImpl method. Code below:
public void testExecuteViewAccessor(){ ViewObjectImpl empDeptVO = this.getEmpDeptVO(); Row row = empDeptVO.createRow(); empDeptVO.insertRow(row); EmpDeptVORowImpl empDeptRow = (EmpDeptVORowImpl)empDeptVO.getCurrentRow(); //calling the EmpDeptVORowImpl method to get the deptId for the deptName 'accounting' Object deptId = empDeptRow.getDeptIdFromViewAccessor("accounting"); System.out.println("DeptId from view accessor: "+deptId); //setting the deptId to the current row's 'Deptno' attribute. empDeptRow.setDeptno((Number)deptId); }

Here is the sample output on running this method using AM tester.

That's it. Now you know how to execute the view accessor(VA) programatically, how to pass the parameters for the view criteria selected in VA definition, how to get and use the results in AMImpl methods.

PS: DeptId and Deptno are used interchangeably in this post.

Thursday, November 11, 2010

ADF UI - selectionListener example for single-select af:table

There are situations when we require to perform some action on selecting a row in a single-select table. For such cases, we need to remove the default selectionListener and specify our own selectionListener method from the backing bean and write our logic within the method.

The generated default selectionListener for the table would be like selectionListener="#{bindings.EmpDeptVO.collectionModel.makeCurrent}". This will actually make the selected row as current row. As we're removing the default selectionListener, we need to call the same default selection listener method in the custom selectionListener method. Then only we can get handle to the selected row.

Sample Use Case:
Suppose I have employees table and when I select a row in the table, immediately I need to show a popup with the selected employee name. Sample application can be downloaded from here.

Implementation Steps:
1. Drop the VO as a table in the jsf page. Remove the default selectionListener and specify your own backing bean method for the selectionListener.
<af:table value="#{bindings.EmpDeptVO.collectionModel}" var="row" rows="#{bindings.EmpDeptVO.rangeSize}" emptyText="#{bindings.EmpDeptVO.viewable ? 'No data to display.' : 'Access Denied.'}" fetchSize="#{bindings.EmpDeptVO.rangeSize}" rowBandingInterval="0" rowSelection="single" id="t1" partialTriggers=":::qryId1 ::ctb1 ::commandToolbarButton1" columnStretching="column:c1" styleClass="AFStretchWidth" columnSelection="multiple" first="0" contentDelivery="immediate" autoHeightRows="10" binding="#{pageFlowScope.ExampleBean.searchResultsTable}" selectionListener="#{pageFlowScope.ExampleBean.rowSelected}">

2. In the custom selectionListener method, call the default selectionListener method which will set the selected row as the current row. We can use ADFUtil.invokeEL() to invoke the same default EL expression method and the selectionEvent as the parameter. Sample code below.
ADFUtil.invokeEL("#{bindings.EmpDeptVO.collectionModel.makeCurrent}", new Class[] { SelectionEvent.class }, new Object[] { selectionEvent });

3. Now, the selected row is set as current row and you can get the current row reference by using the below EL. Now, you can get all attributes of the selected row by using the above reference.
Row selectedRow = (Row)ADFUtil.evaluateEL("#{bindings.EmpDeptVOIterator.currentRow}");

4. Get the attribute value of Ename from the selected row and set it to a pageFlowScope variable say #{pageFlowScope.empName}. Add a popup in the jsf page that displays the #{pageFlowScope.empName} as the selected employee. Write your logic to invoke the popup in the same selectionListener method.

Popup code in the jsf page:
<af:popup id="p1" binding="#{pageFlowScope.ExampleBean.displayNamePopup}"> <af:dialog id="d1" type="ok" title="Alert"> <af:outputText value="You have selected Employee: #{pageFlowScope.empName}" id="ot4"/> </af:dialog> </af:popup>

Backing bean containing the selectionListener method and popup binding:
public class ExampleBean { private RichPopup displayNamePopup; public void rowSelected(SelectionEvent selectionEvent) { ADFUtil.invokeEL("#{bindings.EmpDeptVO.collectionModel.makeCurrent}", new Class[] { SelectionEvent.class }, new Object[] { selectionEvent }); Row selectedRow = (Row)ADFUtil.evaluateEL("#{bindings.EmpDeptVOIterator.currentRow}"); ADFUtil.setEL("#{pageFlowScope.empName}", selectedRow.getAttribute("Ename")); PopupUtil.invokePopup(displayNamePopup.getClientId(FacesContext.getCurrentInstance())); ; } public void setDisplayNamePopup(RichPopup displayNamePopup) { this.displayNamePopup = displayNamePopup; } public RichPopup getDisplayNamePopup() { return displayNamePopup; } }

That's it. When the row is selected, the selectionListener method in the bean is called, current row is set to selected row, stores the current row's Ename attribute to pageFlowScope variable 'empName', invoke the popup programatically, and the same pageFlowScope variable will be displayed in the popup as selected employee name.

Sample screen shots:

Wednesday, November 10, 2010

ADF UI - Creating dropdown or menu buttons

Creating dropdown or menu buttons using ADF is easy. A dropdown menu button is the button with a dropdown icon which will display list of menu items on clicking the button or dropdown icon. Just go through the below steps to create a menu button.

1. Add a af:commandButton or af:toolbarButton where you need to dropdown button. Now, in the 'popup' facet, drag and drop af:menu and add af:menu item(i.e., af:commandMenuItem)s to the af:menu. Sample code below:
<af:commandToolbarButton text="Options" id="commandToolbarButton1" disabled="#{bindings.EmpDeptVO.currentRow==null}" partialTriggers="t1" actionDelivery="none"> <f:facet name="popup"> <af:menu id="m1"> <af:commandMenuItem text="View" id="cmi1" action="view"/> <af:commandMenuItem text="Edit" id="cmi2" action="edit"/> <af:commandMenuItem text="Delete" id="cmi3" actionListener="#{bindings.Delete.execute}" partialTriggers="t1"/> </af:menu> </f:facet> </af:commandToolbarButton>

The above code in Structure window will look like this:

2. The above code will render the menu button as shown below:

3. There are two types of menu buttons:
i. Which will display dropdown list or menu items on clicking the 'dropdown' icon. This button will have a separator (vertical line '|') between the button text and the dropdown icon. It'll look like below. This is actually the default behavior. You can specify action and actionListener for this button and on clicking the button it'll cause navigation or fire actionListener based on the specified action and actionListener respectively.

ii. Which will display drowdown list on clicking the button itself. This button won't have a separator (vertical line '|') between the button text and the dropdown icon. It'll look like below. To get this behavior, you need to set actionDelivery="none" for the button. If you set this property, you can't specify either action or actionListener for the button as it won't fire either action or actionListener.

That's it. You can specify action and actionListener for the menu items in the dropdown menu and do whatever you want.

Sunday, November 7, 2010

ADF UI - Getting all pagedef attributes of a particular VO iterator programatically (find transients among them as well :) )

This might be rare requirement to get handle on pagedef attributes of a particular VO iterator. But, it would be quite useful for some scenarios like when you want to get the values of attributes of a particular iterator present in the current jsff page (not each and every VO attribute) and compare them with the original values to know if the user has changed the attribute through the UI. It would be waste of effort to check all VO attributes if they're changed as the user can only change the attributes present in the UI jsff pages.

But, it's not as easy as getting a reference to bindings (DCBindingContainer) and call the method getAttributeBindngs() on it. Even though it returns all the pagedef attribute bindings, they'll include attributes of all VO iterators in the pagedef. The tricky part is to get attributes of only a particular VO iterator in the pagedef. Here, in this post, I'll explain how to do that.

I did some research and wrote the a method to retrieve all the pagedef attributes of the VO iterator specified by 'VOName' as a parameter. This method also has the logic to find out the transient attributes present the VO. This would be quite useful when you want to find out the transient attributes of a VOIterator in the pagedef and to do logic on them (like skipping them for comparision, etc.,).

Method code in the bean:
public void storePageDefAttrs(String VOName) { DCBindingContainer binding = (DCBindingContainer)ADFUtil.evaluateEL("#{bindings}"); //getting the attribute bindings in the pagedef, it'll contain all pagedef attribute bindings of all VO iterators in pagedef List attrBindings = binding.getAttributeBindings(); //getting iterator for attribute bindings Iterator itr = attrBindings.iterator(); //getting the current row for the VOName ViewRowImpl row = (ViewRowImpl)ADFUtil.evaluateEL("#{bindings." + VOName + "Iterator.currentRow}"); //pageDefAttrs will store pageDef attribute names for the given VO specified by 'VOName' List pageDefAttrs = new ArrayList(); //transientAttrs will store trasient attribute names added in the pagedef for the given VO specified by 'VOName' List transientAttrs = new ArrayList(); //iterating through all attribute bindings while (itr.hasNext()) { AttributeBinding attrBinding = (AttributeBinding)itr.next(); //getting the attribute name String attrName = attrBinding.getName(); //getting the iterator binding for the attribute DCIteratorBinding attrIterBinding = (DCIteratorBinding)ADFUtil.evaluateEL("#{bindings." + attrName + ".iteratorBinding}"); //getting the iterator name for the iterator binding String attrIterBidningName = attrIterBinding.getVOName(); //checking if this attribute's iterator name is equal to the passed VOName if (VOName.equals(attrIterBidningName)) { //if the attributes' iterator name is equal to passed VOName, this attributes belongs to the VO specified by 'VOName'. So adding it to pageDefAttrs. pageDefAttrs.add(attrName); //getting the attribute index int attrIndex = row.getAttributeIndexOf(attrName); //getting the view attribute definition ViewAttributeDefImpl vDef = (ViewAttributeDefImpl)row.getViewDef().getAttributeDef(attrIndex); //checking if it's a transient attribute. boolean transientPageDefAttr = (vDef.getEntityAttributeDef() == null) || (vDef.getEntityAttributeDef().getColumnName() == null); //if it's transient, adding it to transientAttrs list if (transientPageDefAttr) { transientAttrs.add(attrName); } } } //stroing the pagedef attribute names and transient attribute names for the given VOName in the pageFlowScope variables. ADFUtil.setEL("#{pageFlowScope.pageDefAttrs}", pageDefAttrs); ADFUtil.setEL("#{pageFlowScope.trasientPageDefAttrs}", transientAttrs); }

The above code is self explanatory from the comments inline. It takes 'VOName' as a parameter and finally stores all pagedef attributes(including transients) for that VO in the ArrayList 'pageDefAttrs'. It'll also store transient attributes of the VO in the ArrayList 'transientAttrs'.

I devloped a sample application that prints the all attributes and transient attributes present in the pagedef. When you download and run the application, it'll open a search page. Search for a record and select one row and click on 'Edit' button. Now, you'll goto edit page and when you click on 'Show Pagedef Attributes' button, it'll print all attributes as well as the transient attributes present in the pagedef.

Attributes in EmpDeptVO definition:

Attributes in DeptVO definition:

Pagedef file containing some of the attributes from EmpDeptVO and DeptVO:
<?xml version="1.0" encoding="UTF-8" ?> <pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel" version="" id="EditEmployeePageDef" Package="com.demo.fragments"> <parameters/> <executables> <variableIterator id="variables"/> <iterator Binds="EmpDeptVO" RangeSize="25" DataControl="DemoAMDataControl" id="EmpDeptVOIterator"/> <iterator Binds="DeptVO" RangeSize="25" DataControl="DemoAMDataControl" id="DeptVOIterator"/> </executables> <bindings> <attributeValues IterBinding="EmpDeptVOIterator" id="Ename"> <AttrNames> <Item Value="Ename"/> </AttrNames> </attributeValues> <attributeValues IterBinding="EmpDeptVOIterator" id="Job"> <AttrNames> <Item Value="Job"/> </AttrNames> </attributeValues> <attributeValues IterBinding="EmpDeptVOIterator" id="Loc"> <AttrNames> <Item Value="Loc"/> </AttrNames> </attributeValues> <attributeValues IterBinding="EmpDeptVOIterator" id="Mgr"> <AttrNames> <Item Value="Mgr"/> </AttrNames> </attributeValues> <attributeValues IterBinding="DeptVOIterator" id="Dname"> <AttrNames> <Item Value="Dname"/> </AttrNames> </attributeValues> <attributeValues IterBinding="DeptVOIterator" id="Loc1"> <AttrNames> <Item Value="Loc"/> </AttrNames> </attributeValues> <attributeValues IterBinding="EmpDeptVOIterator" id="attribute1"> <AttrNames> <Item Value="attribute1"/> </AttrNames> </attributeValues> <attributeValues IterBinding="EmpDeptVOIterator" id="attribute2"> <AttrNames> <Item Value="attribute2"/> </AttrNames> </attributeValues> </bindings> </pageDefinition>

Ouptput attributes on running the sample application:

So, from the above screen shot you can see our method printed the EmpDeptVO's attributes and transient attributes present in the pagdef correctly.

Enjoy :) !

PS: In case, if you're aware of better approach than the above one, please share with me too. Thank you :)

Saturday, November 6, 2010

ADF UI - Region Interaction: From parent page to child region task flow

If you drop a task flow as a region in a jsf page and if you want to refresh the task flow region based on some action in the jsf, please go through this post.

Sample UseCase:
For example if a Jsf Page contains departments table and on selecting a department from the table and click on button 'Show Employees', it should display the employees in the selected department. But suppose the employee details should come from a different task flow. We need to establish the communication between the parent jsf page and the task flow region in it. Sample application for this example can be downloaded from here.

Implementation Steps:

Task flow refresh Principle:
If you drop a task flow that takes some parameters as a region in a jsff page, the task flow binding will be added in the pagedef file. If you set refresh='ifNeeded' for the task flow binding, the task flow will be re-executed each time when the value for one of the passed parameters got changed. To be clear, here re-execution means the task-flow will re-execute from it's default activity in the task flow diagram.

This example depends on the above principle.

1. Create a jsff page and include departments table and add a button 'Show Employees'.
2. Create a task flow that takes deptId as parameter and fetches the employees present the given department and shows them in a table.

Task flow diagram with input parameter deptId:

3. Specify actionListener for the 'Show Employees' button and in the actionListener method, get the deptId selected in departments table and set to to a pageFlowScope variable.

Java bean containing the actionListener method for 'Show Employees' button:
public class ExampleBean { private Integer deptId; public void buttonClicked(ActionEvent ae){ Row currentDeptRow=(Row)ADFUtil.evaluateEL("#{bindings.DeptVO.currentRow}"); ADFUtil.setEL("#{pageFlowScope.deptId}",currentDeptRow.getAttribute("Deptno")); } public void setDeptId(Integer deptId) { this.deptId = deptId; } public Integer getDeptId() { return deptId; } }

4. Drop the employee details task flow as a region in the jsf page. Pass the same above pageFlowScope variable as a parameter to the dropped taskflow. Specify refresh="ifNeeded" for the task flow binding in pagedef.

Task flow binding in the pagedef:

   <taskFlow id="TaskFlow21"               taskFlowId="/com/demo/taskflows/TaskFlow2.xml#TaskFlow2"               xmlns="http://xmlns.oracle.com/adf/controller/binding"               Refresh="ifNeeded" activation="deferred">       <parameters>         <parameter id="deptId" value="#{pageFlowScope.deptId}"/>       </parameters>     </taskFlow>

That's it. This is how it works: When the user selects department in jsff and clicks on 'Show Employees' button, the actionListener method sets the pageFlowScope variable with the deptId selected and the same will be passed to the dropped task flow. As the task flow re-executes if any of it's input parameter changes, the employees will be queried based on passed deptId and the task flow will refreshed with the corresponding employee details. No 'partialTriggers' is required in this case. Refresh of task flow will be triggered automatically when the input parameter value is changed.

Sample screen shots:

Related Posts with Thumbnails