Showing posts with label BC4J. Show all posts
Showing posts with label BC4J. Show all posts

Thursday, February 7, 2013

How to retrieve Selected Items from selectManyCheckbox using ValueChnageListener

The selectManyCheckbox component creates a component which allows the user to select many values from a series of checkboxes. Below is the code to retrieve selected items from selectManyCheckbox using ValueChangeListener method.

Note:- valueChangeEvent.getNewValue() will return Object value like [Ljava.lang.Object;@fcfd12, need to loop the object arrayList to get the values.

public void myValueChangeListener(ValueChangeEvent valueChangeEvent) {
        Object[] objArr = (Object[])valueChangeEvent.getNewValue();
        for (int x = 0; x < objArr.length; x++) {
            Object obj = objArr[x];
            System.out.println(obj.toString());
       }
}

In Below image, how the selectManyCheckbox will be displayed at run time and user selected check box values will be displayed in Jdeveloper console.

Wednesday, January 16, 2013

Create ADF Input Form Without First Displaying Existing Records

You can create a form that allows a user to enter information for a new record and then commit that record into the data source. While you can choose to use the default ADF Form and then drop the Create operation as a command button, when this type of form is first rendered, it displays the data for the first instance in the collection.

The ADF Creation form allows users to create new instances in the collection without first displaying existing instances, this scenario might be very simple but the new developers find difficulty in creating empty ADF Input Form when page loads for the first time.

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 on Department table. In view controller project create a jspx page then drag and drop DepartmentsView1->Form as ADF Form as shown in below image.


Go to page bindings, in Bindings section click on create control binding and select action item. In create action binding wizard select AppModuleDataControl->DepartmentsView1->Operation->createInsert.


In Executables section click in create executables Binding and select invokeAction item. In Insert invokeAction wizard and follow as shown in below image.


Edit the invokeCreateInsert and set the refresh to renderModel because when ever the page loaded this will execute the createInsert operation by inserting the empty record in the collection.


Run the jspx page and the web page will loaded with empty record.

Thursday, September 20, 2012

Deploy BC4J/EJB application to GlassFish Server

Now deploying the ADF Faces application to the Glassfish server has become easy, users can directly  deploy the application from JDeveloper itself. Deploying the ADF Faces application to the Glassfish server directly runs with Oracle JDeveloper 11.1.2.3.0 onwards.

Note:- If application has model part then first configure JNDI DataSource, In my previous article I have explained how to "Configure JNDI DataSource for OracleDB in GlassFish Server". 

Implementation Steps for BC4J Application:-
  1. Create a fusion web application.
  2. Goto the ViewController project, right click and select project properties. In Project properties wizard select Deployment and edit the WAR deployment profile.
  3. In Platform selection choose Default Platform as "Glassfish 3.1".
  4. Next go to Application, right click and select project properties. In Project properties wizard select Deployment and edit the EAR deployment profile and in Platform selection choose Default Platform as "Glassfish 3.1".
  5. Open AppModule.xml file and select Configurations tab.
  6. Edit AppModuleLocal and modify the DataSource Name from "java:comp/env/jdbc/OracleDS" to "jdbc/OracleDS"
  7. Create Application Server Connection to Glassfish server.
  8. Select application, deploy the EAR file directly to the Glassfish server.
Note: - Above Default Platform determines the platform-specific behavior when packaging the archive for deployment to an Application Server.

Implementation Steps for EJB/JPA Application:-
  1. Create a fusion web application.
  2. Goto the Model project, right click and select project properties. In Project properties wizard select Deployment and edit the JAR deployment profile and in Platform selection choose Default Platform as "Glassfish 3.1".
  3. Goto the ViewController project, right click and select project properties. In Project properties wizard select Deployment and edit the WAR deployment profile and in Platform selection choose Default Platform as "Glassfish 3.1".
  4. Next go to Application, right click and select project properties. In Project properties wizard select Deployment and edit the EAR deployment profile and in Platform selection choose Default Platform as "Glassfish 3.1".
  5. Open persistence.xml file and select Model->Persistence Unit->Connection tab.
  6. In General selection, in JTA DataSource modify "java:/app/jdbc/jdbc/OracleDS" to "jdbc/OracleDS"
  7. In JTA Properties selection, in JTA DataSource Property modify "java:/app/jdbc/jdbc/OracleDS" to "jdbc/OracleDS"
  8. Application like EJB which requires jndi lookup's, we have to change the initial context factory class name. Open the DataControls.dcx file, In ejb-definition tag modify the initial-context-factory class name from "weblogic.jndi.WLInitialContextFactory" to "com.sun.enterprise.naming.SerialInitContextFactory"
  9. Create Application Server Connection to Glassfish server.
  10. Select application, deploy the EAR file directly to the Glassfish server.

Tuesday, August 7, 2012

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.

Monday, June 25, 2012

Get JPA Entity Attributes programmatically in managed bean

Sometimes it is necessary to get database table field column names for further functional process in applications. In one my previous article I have explained one of the use case - Configure Comparison of Row Objects at Run Time, here application module(BC4J) is used to access the ViewObject attributes.

In EJB data control doesn't create any application module or neither have access to application module Api's directly. When the ViewObject is accessed based on the Iterator a dummy object is created using DCDataVo Api. DCDataVo provides little leverage to access certain model layer functionality, so that all Adapter Data Control can use the DCDataVo api to extend to build custom features.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

Here in the below code JPA entity attributes are accessed in managed bean using DCDataVo api.

/**
 * This method will get the View Object based on Iterator
 * Reads the entity attributes(column names)
 * @param actionEvent
 */
public void compareAttributes(ActionEvent actionEvent) {
 DCBindingContainer dcBindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
 DCIteratorBinding deptIter = dcBindings.findIteratorBinding("employeesFindAllIterator");
 ViewObject vo = deptIter.getViewObject();
 int count = 0;
 AttributeDef[] attrDefs = vo.getAttributeDefs();
 for (AttributeDef attrDef : attrDefs) {
  byte attrKind = attrDefs[count].getAttributeKind();
  //Condition to exclude the fk attributes
  if (attrKind == 1) {
   System.out.println(attrDef.getName());
   count++;
  }
 }
}

Displaying the Employee entity attributes.

Thursday, June 7, 2012

Display ADF Dynamic Table based on Declarative SQL Mode In View Object

While working in my previous article "Configure Comparison of Row Objects at Run Time", I struck in constructing the dynamic SQL statement, where I needed to pass the selected column attributes at run time and displays the results using ADF Dynamic Table.

ADF Business Components support constructing design time and run time SQL statements known as "Declarative SQL Mode". Please refer 5.8 Working with View Objects in Declarative SQL Mode in Fusion Developer's Guide to learn more about Declarative View Objects.

Declarative SQL Mode generates SELECT and from options, where required column attributes should be populated in programmatic way. So by this way we can control which are the required column attributes to be queried.

Note: - But ADF Dynamic Table in view layer will not have any clue, which are the attributes selected in model layer. So ADF Dynamic Table will still display all the attributes in view layer. In this article, I'm showing how can we "Display ADF Dynamic Table based on Declarative SQL Mode In View Object". 

So the out come of this scenario looks like below. In the webpage employees details will be displayed with all attributes. Click on the "processDeclarativeSqlQuery" button.


Notice in the below image, only three attributes will be displayed which are passed as dynamic attributes to the SQL query at run time.


You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

The below approach is one of the way to handle the dynamic attributes passed to SQL query at run time and display only those attributes in view layer using ADF Dynamic Table.

Implementation Steps

Create Fusion Web Application with business components from tables based Employees table, open EmployeesView.xml and select Query tab. Click on Edit SQL Query and select the mode as "Declarative" as shown in the below image.


Select the Attribute tab and uncheck "Selected in Query" options for all the Attributes.

Next go to Java tab in AppModule and click on edit java options. Generate the application module class: AppModuleImpl.java and open the AppModuleImpl.java file and the below methods code.

Note: - Below attribute values are hard coded.
/**
 * This method will execute the Declarative Sql mode by filtering
 * required attributes in result set.
 **/
public void processDeclarativeSqlQuery() {
 ViewObjectImpl empVoImpl = this.getEmployeesView1();
 empVoImpl.resetSelectedAttributeDefs(false);
 empVoImpl.selectAttributeDefs(new String[] { "FirstName", "LastName", "Email" });
 System.out.println(empVoImpl.getQuery());
 empVoImpl.executeQuery();

        //Since ADF Dynamic Table in view layer will not have any clue, which are the attributes selected in model layer
        //So updating the displayHint values as "Hide", this value can be checked in view layer using column rendered property
 ArrayList attrList = new ArrayList();
 attrList.add("FirstName");
 attrList.add("LastName");
 attrList.add("Email");
 ViewAttributeDefImpl[] attrDefs = empVoImpl.getViewAttributeDefImpls();
 for (ViewAttributeDefImpl attrDef : attrDefs) {
  byte attrKind = attrDef.getAttributeKind();
  //checks attribute kind for each element in an array of AttributeDefs
  if (attrKind != AttributeDef.ATTR_ASSOCIATED_ROW && attrKind != AttributeDef.ATTR_ASSOCIATED_ROWITERATOR) {
   String columnName = attrDef.getName();
   if (!attrList.contains(columnName)) {
    //Setting the displayHint property value as "HIDE"
    attrDef.setProperty("DISPLAYHINT", "HIDE");
   }
  }
 }
}
Go back to AppModule.xml and select Java tab in client interface section move processDeclarativeSqlQuery, from available to selected block.

In ViewController project, create index.jspx page.
  • From data control palette drag and drop EmployeesView1->Table as ADF Read Only Dynamic Table, set RowSelection as "multiple" and surround the table with panel collection component.
  • From data control palette drop processDeclarativeSqlQuery as ADF Button and set the partial trigger to the employees table.
  • Set the rendered property for the column as "#{bindings.EmployeesView1.hints[def.name].displayHint  eq 'Display'}".
Employees Dynamic Table code will looks like below.
<af:table rows="#{bindings.EmployeesView1.rangeSize}"
    fetchSize="#{bindings.EmployeesView1.rangeSize}"
    emptyText="#{bindings.EmployeesView1.viewable ? 'No data to display.' : 'Access Denied.'}"
    var="row" rowBandingInterval="0"
    value="#{bindings.EmployeesView1.collectionModel}"
    selectedRowKeys="#{bindings.EmployeesView1.collectionModel.selectedRow}"
    selectionListener="#{bindings.EmployeesView1.collectionModel.makeCurrent}"
    rowSelection="multiple" id="t1" styleClass="AFStretchWidth" partialTriggers="::cb1">
 <af:forEach items="#{bindings.EmployeesView1.attributeDefs}" var="def">
  <af:column headerText="#{bindings.EmployeesView1.labels[def.name]}" sortable="true"
       sortProperty="#{def.name}" id="c1"
       rendered="#{bindings.EmployeesView1.hints[def.name].displayHint  eq 'Display'}">
   <af:outputText value="#{row[def.name]}" id="ot1"/>
  </af:column>
 </af:forEach>
</af:table>

Monday, May 28, 2012

Commit the child taskflow transaction in parent taskflow transaction using DataContolFrame Api

In this post I'm sharing sample for how can we use "DataContolFrame" to commit the child taskflow transaction in parent taskflow transaction. 

Take a scenario, where we have two taskflows. The parent taskflow contain employee table and child taskflow contains selected employee rows. Alter the values and save, once clicking on Save button will save the data into cache. Now in parent taskflow user can click on Commit button would commit all the changes down in the child taskflow to DB, Rollback button will undo all changes done in child taskflow.

Here DataControlFrame api is used to commit/rollback the data at taskflow controller level. A Data Control Frame is the container associated with a task flow that contains data control instances. To specify whether data control instances are shared between the calling and called task flows, you must set a data-control-scope value of either shared or isolated on the called bounded task flow. In above scenario we can use shared data-control-scope. 

[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

Implementation Steps

Create Fusion Web Application with business components from tables based on Departments, Employees table, create a new extended object from Employees View as shown in below image.


Open the AppModule and select Data Model tab move "childEmployeesView" from available view objects to data model.


Next go to Java tab in AppModule and click on edit java options. Generate the application module class: AppModuleImpl.java.

Open the AppModuleImpl.java file and the below methods code.
/**
 * This method create's the view crietria at the runtime,
 * set the IN clause operator by accessing the ChildEmployeesView1
 * @param empList
 */
public void populateSelectedRowData(List empList) {
 try {
  if (empList.size() > 0) {
   //cleanUpChildEmployeesView1 just in case before populating new set of rows
   cleanUpChildEmployeesView1();
   ViewObject childEmpVo = getChildEmployeesView1();
   ViewCriteria childEmpVC = childEmpVo.createViewCriteria();
   ViewCriteriaRow childEmpVCRow = childEmpVC.createViewCriteriaRow();
   ViewCriteriaItem childEmpVCRowItem = childEmpVCRow.ensureCriteriaItem("EmployeeId");
   childEmpVCRowItem.setOperator("IN");
   for (int i = 0; i < empList.size(); i++) {
    childEmpVCRowItem.setValue(i, empList.get(i));
   }
   childEmpVC.addElement(childEmpVCRow);
   childEmpVo.applyViewCriteria(childEmpVC);
   childEmpVo.executeQuery();
   System.out.println("populateSelectedRowData - Estimated Row Count - " +
          childEmpVo.getEstimatedRowCount());
  }
 } catch (Exception e) {
  e.printStackTrace();
 }
}

/**
 * Clean up the childemployeesView existing rows from collection.
 */
public void cleanUpChildEmployeesView1() {
 ViewObject childEmpVO = (ViewObject)this.getChildEmployeesView1();
 //avoid validation when navigating rows
 childEmpVO.setRowValidation(false);
 while (childEmpVO.hasNext()) {
  childEmpVO.setCurrentRow(childEmpVO.next());
  childEmpVO.removeCurrentRowFromCollection();
 }
}

/**
 * This method will update the departmentId for selected Employees rows
 * @param empKeysList
 * @param departmentId
 */
public void updateAllChildEmployeesRows(List empKeysList, String departmentId) {
 if (empKeysList != null && empKeysList.size() > 0) {
  ViewObject empVO = (ViewObject)this.getEmployeesView1();
  Iterator iter = empKeysList.iterator();
  Key rowKey = null;
  Row[] matchingInvoiceRows = null;
  Row currRow = null;
  while (iter.hasNext()) {
   //get the key for the invoice row
   rowKey = (Key)iter.next();
   //find the row by key in InvoiceVO
   matchingInvoiceRows = empVO.findByKey(rowKey, 1);
   if (matchingInvoiceRows != null && matchingInvoiceRows.length > 0)
    currRow = matchingInvoiceRows[0];
   if (currRow != null) {
    if (departmentId != null) {
     currRow.setAttribute("DepartmentId", departmentId);
    }
   }
  }
 }
}

Go back to AppModule.xml and select Java tab in client interface section move populateSelectedRows, updateAllChildEmployeesRows from available to selected block.


In ViewController project, create below mentioned bounded taskflows.
  1. "EmployeeDetails-btf" and set the Transaction as "Always Begin New Transaction", select the data-control-scope "Shared data controls with calling task flow".
  2. "EmployeeEdit-btf" and set the Transaction as "Always Use Existing Transaction", select the data-control-scope "Shared data controls with calling task flow" and create two pageFlowScope parameters as empList and empKeyList.
Open EmployeeDetail-btf, from component palette drop view as "EmployeeDetails" and generate EmployeeDetails.jsff page and "EmployeeDetailsBean.java". Add the EmployeeDetailsBean.java file in taskflow with scope requestScope.
  • From data control palette drag and drop EmployeesView1->Table as ADF Read Only Table, set RowSelection as "muliptle". 
  • Surround the table with panel collection component and add Edit button with text as "Edit". Create the actionListener method for edit button as "onEditAction".
  • Add two more button to the page Commit/Rollback and create actionListener method as "onCommit","onRollback" respectively.
  • From component palette drop popup inside the page and drop "EmployeeEdit-btf" as region inside popup, set the popupCanceledListener, popupFetchListener as show in the below code.
 <af:popup childCreation="deferred" autoCancel="disabled" id="p1" contentDelivery="lazyUncached"
              popupCanceledListener="#{EmployeeDetailsBean.popupCancelled}"
              popupFetchListener="#{EmployeeDetailsBean.poupFetchListener}" binding="#{EmployeeDetailsBean.popup}">
        <af:panelWindow id="pw1" title="Edit Employees">
            <af:region value="#{bindings.EmployeeEditbtf1.regionModel}" id="r1"
                       regionNavigationListener="#{EmployeeDetailsBean.hearNavigation}"/>
        </af:panelWindow>
  </af:popup>

Open the EmployeeDetailsBean.java file and copy the below methods code.
private RichPopup popup;
private RichTable empTable;

public EmployeeDetailsBean() {
}

public void setPopup(RichPopup popup) {
 this.popup = popup;
}

public RichPopup getPopup() {
 return popup;
}

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

public RichTable getEmpTable() {
 return empTable;
}

public void popupCancelled(PopupCanceledEvent popupCanceledEvent) {
 ADFContext.getCurrent().getPageFlowScope().put("forceActivate", "false");
 System.out.println("popupCancelled");
}

public void poupFetchListener(PopupFetchEvent popupFetchEvent) {
 ADFContext.getCurrent().getPageFlowScope().put("forceActivate", "true");
 System.out.println("poupFetchListener");
}

public void hearNavigation(RegionNavigationEvent regionNavigationEvent) {
 this.popup.hide();

 AdfFacesContext.getCurrentInstance().addPartialTarget(this.empTable);
 System.out.println("Finished closing popup");
}

public void onEditAction(ActionEvent actionEvent) {
 RowKeySet selectedEmps = getEmpTable().getSelectedRowKeys();
 if (selectedEmps.size() > 0) {
  //Restart the taskflow
  DCBindingContainer dc = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
  DCTaskFlowBinding tf = (DCTaskFlowBinding)dc.findExecutableBinding("EmployeeEditbtf1");
  tf.getRegionModel().refresh(FacesContext.getCurrentInstance());

  Iterator selectedEmpIter = selectedEmps.iterator();
  DCBindingContainer bindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
  DCIteratorBinding empIter = bindings.findIteratorBinding("EmployeesView1Iterator");
  RowSetIterator empRSIter = empIter.getRowSetIterator();
  List selectedRowKeys = new ArrayList();
  List SelectedDeptIdRowValue = new ArrayList();
  while (selectedEmpIter.hasNext()) {
   Key key = (Key)((List)selectedEmpIter.next()).get(0);
   selectedRowKeys.add(key);
   Row currentRow = empRSIter.getRow(key);
   SelectedDeptIdRowValue.add(currentRow.getAttribute("EmployeeId"));
  }

  ADFContext.getCurrent().getRequestScope().put("empList", SelectedDeptIdRowValue);
  ADFContext.getCurrent().getRequestScope().put("empKeysList", selectedRowKeys);
  RichPopup.PopupHints hints = new RichPopup.PopupHints();
  this.popup.show(hints);
 }
}

public void onCommit(ActionEvent actionEvent) {
 Map sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
 BindingContext context = (BindingContext)sessionMap.get(BindingContext.CONTEXT_ID);
 String currentFrameName = context.getCurrentDataControlFrame();
 DataControlFrame dcFrame = context.findDataControlFrame(currentFrameName);
 dcFrame.commit();
 dcFrame.beginTransaction(null);
}

public void onRollBack(ActionEvent actionEvent) {
 Map sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
 BindingContext context = (BindingContext)sessionMap.get(BindingContext.CONTEXT_ID);
 String currentFrameName = context.getCurrentDataControlFrame();
 DataControlFrame dcFrame = context.findDataControlFrame(currentFrameName);
 dcFrame.rollback();
 dcFrame.beginTransaction(null);
 AdfFacesContext.getCurrentInstance().addPartialTarget(this.empTable);
}

Now go to EmployeeDetails.jsff page binding and set the condition for taskflow-EmployeeEditbtf1 executables as shown in below image.



Open the EmployeeEdit-btf, create the flow as shown below.



  • Drag and drop populateSelectedRowData from data control and set the parameter value for empList as "#{pageFlowScope.empList}".
  • From component palette drop view as "EmployeeEdit" and generate EmployeeEdit.jsff page and "EmployeeEditBean.java". Add the EmployeeEditBean.java file in taskflow with scope backingBean.
  • Draw the control flow case from  populateSelectedRowData to EmployeeEdit and keep default outcome
  • Drop  EmployeesView1->Execute from data control palette.
  • Draw the control flow case from EmployeeEdit to Execute and outcome as save.
  • Now add two Task Flow Return and name them as Save and Cancel.
  • Draw the control flow case from EmployeeEdit to Cancel and outcome as exit.
  • Draw the control flow case from Execute to Save and outcome as Execute.
Open EmployeeEdit.jsff page.
  • From data control palette drop ChildEmployeesView1->Table as ADF Table.
  • Drop DepartmentView1->Single Selection as ADF Select One Choice and select display attribute as departmentId and create valueChangeListener method as "getSelectedDeptId".
  • Go to page bindings page, add method action updateAllChildEmployeesRows  set the parameters value for empKeyList as "#{pageFlowScope.empList}" and departmentId as "#{pageFlowScope.departmentId}".
  • From component palette add two button as Save/Cancel and set the action to save/exit respectively.
Open the EmployeeEditBean page and add the below code.
public void getSelectedDeptId(ValueChangeEvent valueChangeEvent) {
        ADFContext.getCurrent().getPageFlowScope().put("departmentId", valueChangeEvent.getNewValue());
    }

Last step create the index.jspx page and drop EmployeeDetail-btf as region. Run the index.jspx page and page should look like below.


Select multiple employee rows and click on edit button.


Select the required DepartmentId and click on Save button will save the data in cache not to the DB. If Cancel button is clicked no action will happen, it will just close the popup window.


Now we can notice the departmentId for the selected employee rows as updated. In this page if Commit button is clicked DataControlFrame will update the child taskflow values to the database and Rollback button will undo all the changes.

Thursday, May 24, 2012

Dynamic Control Flow Case using ActionEvent

Here is a scenario where we need to navigate from one page to another page based on some condition. In design time set the 'Action' property of UI component can be used to navigate between pages, but here Action property can't be used since navigation is based on condition. In this article will see how can we programmatically handle the control flow case in managed bean using ActionEvent.

This can be achieved using handleNavigation method from NavigationHandler class. But direct invocation of methods on the NavigationHandler doesn't conform with JSF specification and it bypasses JSF lifecycle invoke application phase, also pending changes may not be submitted.

Take an example, here we have DeptBrowsePage which display departments table with multiple select option enabled and with edit button. If user selects the single row and click on edit Control Flow Case should go to DeptFormPage and if multiple rows selected it should go to DeptTablePage.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0(11g R2) + HR Schema]

The following code illustrates the Control Flow Case dynamically at run time using handleNavigation method. Please download the application to see the entire scenario.

Note: - Here created the bindings for buttons DeptForm, DeptButton respective with getDeptFormButton(), getDeptTableButton() and buttons rendered property made false.
/**
* In this method first looking for the selected row keys
* Based on the condition, queue the action event on respective command button
* @return
*/
public String navigateHanlderMethod() {
        //Get the selected rowkey values
        RowKeySet selectedDepts = getDeptTable().getSelectedRowKeys();
        if (selectedDepts.size() == 1) { //If Single row is selected
            ActionEvent actionEvent = new ActionEvent(this.getDeptFormButton());
            actionEvent.queue();
        } else if (selectedDepts.size() > 1) { // If multiple rows are selected
            List selectedRowKeys = getSelectedRowKeys();
            Map pfScope = ADFContext.getCurrent().getPageFlowScope();
            pfScope.put("deptList", selectedRowKeys);
            ActionEvent actionEvent = new ActionEvent(this.getDeptTableButton());
            actionEvent.queue();
        }
        return null;
 }

Output: Run the index.jspx page.


Select single row and click on the Edit button should take to DeptFormPage.jspx and display only selected row.


Select multiple rows and click on the Edit button should take to DeptTablePage.jspx and display only selected rows.

Monday, May 21, 2012

Get ViewObject attributes pro-grammatically and display in Shuttle component

In this article, I'm trying to explain how can ViewObject attributes be read pro-grammatically and display these attributes in ADF Shuttle component.

The ADF Shuttle component is appropriate for when the business process requires sequencing selected objects for further action, and the user needs to see the source data and items selected for process. The above scenario can be useful when you want to compare two objects, where in user can quickly add and remove items from the pool. Here database table column will be displayed as comparable fields.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

Implementation steps

Create a Fusion Web Application, click on ADF Business Components and create business components from table based on Employees. Create a CompareAttributes.java class file and add the below code.

public class CompareAttributes {
 private String columnName;
 private String columnAliasName;

 public CompareAttributes() {
  super();
 }

 public CompareAttributes(String columnName, String columnAliasName) {
  super();
  this.columnName = columnName;
  this.columnAliasName = columnAliasName;
 }

 public void setColumnName(String columnName) {
  this.columnName = columnName;
 }

 public String getColumnName() {
  return columnName;
 }

 public void setColumnAliasName(String columnAliasName) {
  this.columnAliasName = columnAliasName;
 }

 public String getColumnAliasName() {
  return columnAliasName;
 }
}

Open the AppModule.xml and goo to Java tab in AppModule and click on edit java options. Generate the application module class: AppModuleImpl.java and open the AppModuleImpl.java file and the below method code.

/**
* This method reads the ViewObject attributes and populate CompareAttributes list 
* @return CompareAttributes list
*/
public List getCompareAttributes() {
 ViewObjectImpl vo = getEmployeesView1();
 ViewAttributeDefImpl[] attrDefs = vo.getViewAttributeDefImpls();
 int count = 0;
 List compareAttrs = new ArrayList();
 for (ViewAttributeDefImpl attrDef : attrDefs) {
  byte attrKind = attrDefs[count].getAttributeKind();
  //checks attribute kind for each element in an array of AttributeDefs
  if (attrKind != AttributeDef.ATTR_ASSOCIATED_ROW && attrKind != AttributeDef.ATTR_ASSOCIATED_ROWITERATOR) {
   String columnName = attrDef.getName();
   String columnAliasName = attrDef.getAliasName();
   compareAttrs.add(new CompareAttributes(columnName, columnAliasName));
   count++;
  }
 }
 return compareAttrs;
}

Go back to AppModuleImpl.java and select Java tab in client interface section move getCompareAttributes from available to selected block.


In ViewController project, create index.jspx page and generate page definition page. Go to bindings tab and insert methodAction as "getCompareAttributes" from AppModuleDataControl.

Create the managedBean as "IndexBean", set the scope as pageFlowScope and copy the below code.

public List getShuttleList() {
        BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();
        OperationBinding operBind = bindings.getOperationBinding("getCompareAttributes");
        List<CompareAttributes> compareAttr = (List)operBind.execute();

        List shuttleList = new ArrayList();
        for (int i = 0; i < compareAttr.size(); i++) {
            CompareAttributes attr = compareAttr.get(i);
            SelectItem item = new SelectItem(i, attr.getColumnName(), attr.getColumnAliasName());
            shuttleList.add(item);
        }
        return shuttleList;
    }

Open index.jspx page and from component palette drag and drop the Shuttle Component, In Insert shuttle window for "Bind to list (select items) bind to #{pageFlowScope.IndexBean.shuttleList}" as shown below.


Run the index.jspx page, now user can quickly add and remove items from the pool.


Tuesday, May 15, 2012

How to add attribute from related entity in view object

Take as scenario where we need to retrieve the related objects attributes in the same result set. In this article, I'm trying to explain how can we add attribute from related entity in view object. 

In BC4J, this scenario can be implemented using Entity Objects facility provided in View Object layer. These entity objects are used by the view object for accessing the related objects attributes and will be exposed in data control layer automatically.

Implementation Steps

Create Fusion Web Application, click on ADF Business Components and create business components from table based on Departments, Employees.

Open the EmployeesView.xml view object and select the Entity Objects tab. Move the Departments entity from available pool to selected pool as shown below.


Go to the Attributes tab, click on add attribute from entity. In Attributes window under Departments entity section move DepartmentName from available pool to selected pool as shown below.


Run the ADF Module Tester(application module) and select EmployeesView1 in AppModule. Now we can notice DepartmentName attribute is also displayed for the employee result set.

Friday, May 11, 2012

Display multiple selected rows from ADF table in a popup window

In this post I'm sharing sample for how to display multiple selected rows from ADF table in a popup window.

Solution
Create a new extended view from the parent view. In Application Module create a view criteria with IN clause at run time and execute the view, this is one of the approach to display the contents of all the selected rows in a popup window.

You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.0.0 (11g R2) + HR Schema]

Implementation Steps

Create Fusion Web Application with business components from tables based on Departments table. Now create a new extended object from DepartmentsView as shown in below image.


 Open the AppModule and select Data Model tab move "childDepartmentsView" from available view objects to data model.


 Next go to Java tab in AppModule and click on edit java options. Generate the application module class: AppModuleImpl.java.
Open the AppModuleImpl.java file and the below method code.

/**
 * This method create's the view crietria at the runtime,
 * set the IN clause operator by accessing the ChildDepartmentsView1
 * @param deptList
 */
public void populateSelectedRows(List deptList) {
 try {
    ViewObject childDeptVo = getChildDepartmentsView1();
    ViewCriteria childDeptVC = childDeptVo.createViewCriteria();
    ViewCriteriaRow childDeptVCRow = childDeptVC.createViewCriteriaRow();
    ViewCriteriaItem childDeptVCRowItem = childDeptVCRow.ensureCriteriaItem("DepartmentId");
    childDeptVCRowItem.setOperator("IN");
    for (int i = 0; i < deptList.size(); i++) {
      childDeptVCRowItem.setValue(i, deptList.get(i));
    }
    childDeptVC.addElement(childDeptVCRow);
    childDeptVo.applyViewCriteria(childDeptVC);
    childDeptVo.executeQuery();
 } catch (Exception e) {
    e.printStackTrace();
 }
}   

Go back to AppModuleImpl.java and select Java tab in client interface section move populateSelectedRows from available to selected block.


In ViewController project, create index.jspx page and drag and drop DepartmentsView1->Table as ADF Read-only Table with rowSlection as multiple and create the backingBean as "IndexBean". Surround the table with panel collection, add the toolbar, drop button inside toolbar and name as "Edit".

From component palette drag and drop ADF popup, ContinentDelivery as lazyUncached. Drop dialog inside the popup, Type as none. Now drag and drop  ChildDepartmentsView1->Table as ADF Table.

Open the index.jspx page, bind the departments table to the backing bean as show below.


Create the ActionListener method called "editAction" for Edit button.


Open the IndexBean backing bean and add the below method code.

private List selectedRowKeys;

public void editAction(ActionEvent actionEvent) {
        getSelectedRowKeys();

        BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();
        OperationBinding oper = bindings.getOperationBinding("populateSelectedRows");
        oper.execute();

        ExtendedRenderKitService erkService =
            Service.getService(FacesContext.getCurrentInstance().getRenderKit(), ExtendedRenderKitService.class);
        erkService.addScript(FacesContext.getCurrentInstance(),
                             "var hints = {autodismissNever:true}; " + "AdfPage.PAGE.findComponent('p1').show(hints);");
    }

    public List getSelectedRowKeys() {
        selectedRowKeys = null;
        RowKeySet selectedDepts = getDeptTable().getSelectedRowKeys();
        Iterator selectedDeptIter = selectedDepts.iterator();
        DCBindingContainer bindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
        DCIteratorBinding deptIter = bindings.findIteratorBinding("DepartmentsView1Iterator");
        RowSetIterator deptRSIter = deptIter.getRowSetIterator();
        selectedRowKeys = new ArrayList();
        while (selectedDeptIter.hasNext()) {
            Key key = (Key)((List)selectedDeptIter.next()).get(0);
            Row currentRow = deptRSIter.getRow(key);
            selectedRowKeys.add(currentRow.getAttribute("DepartmentId"));
        }
        return selectedRowKeys;
    } 

Go to Bindings tab in index.jspx page, add populateSelectedRows method action and map the parameter to backingBeanScope variable.


Run the index.jspx page, select the multiple rows and click on edit button. Popup window should contains all the selected rows as shown below.