Dec 20, 2013

Recently i ran into a situation where i had to specify a default value for bind variable in ViewAccessor  and access the value in the lookup view object. Upon analysis, I found that when i accessed the value using bind variable accessor, the value was always null but in the overridden executeQueryForCollection method i was always receiving the default value, which i had specified, in the params parameter. Needless to say i did not want to access the params object for accessing the bind value, so to fix the issue i changed the RowLevelBinds property of the view accessor to false. Note that this property should only be used if your rowset of the lookup does not change depending upon the current rows’ attribute which essentially means that if you have to fetch a bunch of data like let’s say a list of all organizations and you want to avoid re-querying of the data based on your current rows’ (the view object row where you are using the lookup) attributes you are better off by using the RowLevelBinds=false.

Doing so leads to the following benefits

a) Avoids re-querying of the database b)More important, in my case be able to access the default bind value that i had specified on the viewaccessor using bind variable accessor.

 

Note: At this point of time i do not know whether this is a bug or the intended behaviour that causes the default value to be discarded when using the bind variable accessor.

Posted on Friday, December 20, 2013 by Ramandeep Singh Nanda

Dec 14, 2013

ADF provides strong transaction handling mechanisms for database based applications which are backed by entity and view objects. But what if you have a application which does not use database ? How do you then detect changes to your data ?.  Let’s say you have a web service backed programmatic view objects and you have extended your application to work without a database and user saves some data and clicks on update record ? How would you then verify a) whether the data has changed b) handle commits and rollback c) warn user of uncommitted data changes

In this post i will share the solution to above problems.

1) Detecting changes: If you are using data controls and bindings then you can detect changes when the user submits the data by using the following snippet of code. Note that doing this is very relevant as you do not want to call the backend web service or execute some update code where no action is required.

DCBindingContainer dcBindingContainer=(DCBindingContainer)
BindingContext.getCurrent().getCurrentBindingsEntry();
if(dcBindingContainer.getDataControl().isTransactionModified()){
// Handle update calls to your service here
}
else{
//well nothing to do here maybe notify the user of the same
JSFUtils.addFacesInformationMessage("No change detected");
}


2. Handling Commit or Rollback: Now to handle commits or rollback you can use the following code snippet also note that you must rollback or commit the transaction manually.



//To commit the transaction
dcBindingContainer.getDataControl().commitTransaction();
//To rollback the transaction
dcBindingContainer.getDataControl().rollbackTransaction();


3. Implementing Uncommitted Data Changes warning: To prevent navigation between regions you can implement your own logic on a similar lines as shown in the following code snippet. The backing bean snippet is shown below followed by the test page code.



public class NavBacking implements Serializable {
private static final long serialVersionUID = 1L;
//this will hold the value of task flow id being passed in the setter
private String newTaskFlowId;
//this is where the value of task flow id is picked from
private String taskFlowId

public void setTaskFlowId(String taskFlowId) {
//here we will override the setter to set the taskflow value into our own variable for the time being
this.newTaskFlowId=taskFlowId;

}
/**
* This method is used to check whether the transaction is dirty or not
* and then it launches a popup to confirm from user whether he wants to
* discard the changes or not
* @return
*/
public String checkChanges() {
DCBindingContainer dcBindingContainer=(DCBindingContainer)
BindingContext.getCurrent().getCurrentBindingsEntry();
if(dcBindingContainer.getDataControl().isTransactionModified()){
/**
*check placed here to confirm whether the oldtaskflow id and new taskflow id are same
*and if they are it allows the change
*
*/

if(!taskFlowId.equals(newTaskFlowId)){
FacesContext context = FacesContext.getCurrentInstance();
ExtendedRenderKitService erks =
Service.getRenderKitService(context, ExtendedRenderKitService.class);
//show popup
erks.addScript(context,"AdfPage.PAGE.findComponent('"+popupId +"').show();");
}
}
else{
this.taskFlowId=newTaskFlowId;
}

return null;
}
/**
* If the user insists on discarding changes rollback the transaction
* @return
*/
public String okAction() {
DCBindingContainer dcBindingContainer=(DCBindingContainer)
BindingContext.getCurrent().getCurrentBindingsEntry();
dcBindingContainer.getDataControl().rollbackTransaction();
this.taskFlowId=newTaskFlowId;
return null;
}
}

//Unbounded taskflow page which is used to call the bounded taskflow

<af:popup id="pp3" animate="default" childCreation="deferred"  clientComponent="true">
<af:dialog id="dg1" closeIconVisible="false" type="none"
title="Uncommitted Data Warning" >
<f:facet name="buttonBar">
<af:toolbar id="tb1">
<af:commandButton id="cb1"
text="OK" immediate="true" action="#{viewScope.NavBacking.okAction}"/>
<af:commandButton id="cb2"
text="CANCEL" immediate="true" action=" "/>
</af:toolbar>
</f:facet>
<af:inputText id="opt1" readOnly="true" wrap="hard"
value="You have made some changes are you sure you want to continue"/>
<af:spacer id="sp2" height="5"/>
</af:dialog>
</af:popup>
// now you have to ensure that each command link enforces a call to checkChanges

<af:commandLink text="pageName"
visible="true" immediate="true"
action="#{viewScope.NavBacking.checkChanges}"
id="cl2">
<af:setPropertyListener type="action"
from="taskflowIdGoesHere"
to="#{viewScope.NavBacking.taskFlowId}"/>
</af:commandLink>

Note: For this code to work your bounded taskflow must share the datacontrol with the calling unbounded taskflow.

Screenshots:-







Links and references:-



Checking Dirty Data by Jobinesh

Posted on Saturday, December 14, 2013 by Ramandeep Singh Nanda