http://people.inf.elte.hu/kiss/14kor/gant_chart_pivot_table.htm
Oracle ADF, JAVA/J2EE application developer. Through this blog i am sharing my experience and knowledge.
Monday, April 30, 2018
Retrieving any bean with any scope
GOFJ : Retrieving any bean with any scope
GOFJ ? We'll get back to that.
For now I'll just introduce a way of retrieving your managed bean instance in any place of your project's java classes :
Your beanName is specified in either adf-config either faces-config depending on what you've choosed. Also, for backing beans, "backingBeanScope.backing_pageName" is the beanName variable to use since it's the way it's generated by JDeveloper.
That's how it's done, in the Good Old Fashionned Java way.
For now I'll just introduce a way of retrieving your managed bean instance in any place of your project's java classes :
public static Object retrieveManagedBean(String beanName, Class beanClass) {
FacesContext fc = FacesContext.getCurrentInstance();
ValueExpression ve = fc.
getApplication().
getExpressionFactory().
createValueExpression(fc.getELContext(), "#{"+beanName+"}", beanClass);
return ve.getValue(fc.getELContext());
}
Your beanName is specified in either adf-config either faces-config depending on what you've choosed. Also, for backing beans, "backingBeanScope.backing_pageName" is the beanName variable to use since it's the way it's generated by JDeveloper.
That's how it's done, in the Good Old Fashionned Java way.
Wednesday, April 25, 2018
JDeveloper: Prevent Navigation from Field on Failed Validation
This post shows how to implement a use case where you don’t want the user to leave a field which has a validation error. ADF does a good job enforcing that all validations are checked at the time you submit the data. However, if you want the user to correct an error in a field directly, you have to implement it yourself.
Use Case
A validation error can be a mandatory field which the user has not filled in or a where the user has filled in wrong data. In such a case you want that the user must correct the error before she/he is allowed to move to the next field.
Implementation
We start with a fragment whihc holds two af:inputText components. One we use to simulate a mandatory input text and the other for a normal input text field.

The ‘Test’ button is used to submit the form. If we hit the Test button without any data in the fields we get

as hte ID field is marks required. One you enter something into this field you can successfully submit the form

That is the normal behavior ADF gives you out of the box. The use case we implement here requires, that the user can’t leave the field once an error is shown for the field. So if the user sets the cursor to the ID field he can’t navigate away from it until he fixes the error. He can’t even click hte button. ADF would allow the user to leave the ID field to enter some value into the Name field.
So how do we prevent the user leaving the field by clicking in another field or clicking on a button?
We use an af:clientListener which listens for the ‘blur’ event checking if the field contains a value. If not, we set the focus back to the component and cancel the ongoing even. Setting the focus back to the component is essential as the blur event tell us that we loose the focus. This only happens if the user navigates away from the field.
function setFocusWhenValidateFail(event) { var element = event.getSource(); var val = element.getValue(); var cid = element.getClientId(); console.log("Value=" + val); if (val == null) { element.focus(); event.cancel(); } }
The JavaScript function above shows this. This function is called via an af:clientListener we added to the af:inputText component
<af:inputText label="ID (mandatory)" id="it1" required="true" value="#{bindings.myId1.inputValue}" autoSubmit="true"> <af:clientListener method="setFocusWhenValidateFail" type="blur"/> </af:inputText>
This is it. But wait, what if we like to check if the value entered by the user is valid?
Now, this add another complexity. For this we need to either code the validation in JavaScript or we have to call a bean method which can do the complex check on hte server side model. For easy checks it’s no problem to implement them in JavaScript in the ‘else’ part of the function above.
To call a server side method we need to add an af:serverListener which calls a bean method
<af:inputText label="ID (mandatory)" id="it1" required="true" value="#{bindings.myId1.inputValue}" autoSubmit="true"> <af:clientListener method="setFocusWhenValidateFail" type="blur"/> <af:serverListener type="validateServerListener" method="#{viewScope.InputValidationBean.handleValidationEvent}"/> </af:inputText>
and we change the JavaScript function
function setFocusWhenValidateFail(event) { var element = event.getSource(); var val = element.getValue(); var cid = element.getClientId(); console.log("Value=" + val); if (val == null) { element.focus(); event.cancel(); } else { console.log("call server with " + cid + " and " + val) //call bean method validateServerListener AdfCustomEvent.queue(element, "validateServerListener", { fcid : cid, fvalue : val }, false); event.cancel(); } }
Note that we add two parameters to the call to the bean method. The first parameter fcid is the client id of the component which calls the bean method. The second parameter fvalue is the value the user has entered into the field. We see why we need the parameters when we talk about the bean method.
In the bean we implement the custom validateServerListener method. First we get the two parameters from the ClientEvent and log them to the console. At this point we can e.g. call an application module method with the parameter we got. In this simple same we just check the value for a specific value, in this case ’88’. When the value is ’88’ we add a FacesMessage to the component with the clientId we got as second parameter.
However, just adding the FacesMessage wont be enough. At this point he focus has already shifted out of the component and the message would not displayed until the component is selected again. The event.cancel() in the JavaScript function does not prevent that the focus is shifted out of the component. The solution is to reset the focus to the component from the bean again. For this we add JavaScript code which will be executed after the event has finished. The JavaScript searches for the component by it’s Id and then calls component.focus() to set the focus back to this component.
public void handleValidationEvent(ClientEvent ce) { // get client id from event Object obj = ce.getParameters().get("fcid"); String clientId = ""; if (obj != null) { clientId = obj.toString(); } // get field value from event String val = ""; Object obj2 = ce.getParameters().get("fvalue"); if (obj2 != null) { val = obj2.toString(); } logger.info("client id =" + clientId + " value=" + val); // do a check if hte value if OK // here we check against 88 to keep it simple. You can check against other model values here too! if ("88".equals(val)) { // check failed -> add message to the component and set the focus back to the component FacesContext facesContext = FacesContext.getCurrentInstance(); FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Error", "Wrong vlaue"); facesContext.addMessage(clientId, msg); // javascript to set focus to component identified by it's clientId String script = "var t=document.getElementById('" + clientId + "::content');t.focus();"; writeJavaScriptToClient(script); } } //generic, reusable helper method to call JavaScript on a client private void writeJavaScriptToClient(String script) { FacesContext fctx = FacesContext.getCurrentInstance(); ExtendedRenderKitService erks = null; erks = Service.getRenderKitService(fctx, ExtendedRenderKitService.class); erks.addScript(fctx, script); }
Monday, April 16, 2018
ADF javascript by pressing tab(At the end) need to set focus on first item
function tabOutOfLOVField(evt) {
keyCode = evt.getKeyCode();
if (keyCode == AdfKeyStroke.TAB_KEY) {
//alert('Enterde into JS Code');
var lastField = evt.getSource();
var firstField = lastField.findComponent("it2");
firstField.focus();
evt.cancel();
}
}
keyCode = evt.getKeyCode();
if (keyCode == AdfKeyStroke.TAB_KEY) {
//alert('Enterde into JS Code');
var lastField = evt.getSource();
var firstField = lastField.findComponent("it2");
firstField.focus();
evt.cancel();
}
}
Monday, April 9, 2018
ADF Programmatically Commit & Rollback
Committing through java code in your managed bean:
DCBindingContainer bindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
OperationBinding operationBinding = bindings.getOperationBinding(“Commit”);
operationBinding.execute();
Rollback transaction through java code in your managed bean:
DCBindingContainer bindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
OperationBinding operationBinding = bindings.getOperationBinding(“Rollback”);
operationBinding.execute();
Pay attention to the operation binding names, if you have CRUD operations from different application modules within the same page, those names will differ (generally: Commit1, Rollback1 etc)
https://adfgok.wordpress.com/2014/04/23/adf-programmatically-commit-rollback/
Sunday, April 8, 2018
Display faces message at bean level
getmsg(" we can type our own message", it29.getClientId());
public void getmsg(String msg, String clien_id) {
FacesContext context = FacesContext.getCurrentInstance();
FacesMessage fm = new FacesMessage(msg);
fm.setSeverity(FacesMessage.SEVERITY_ERROR);
context.addMessage(clien_id, fm);
}
public void getmsg(String msg, String clien_id) {
FacesContext context = FacesContext.getCurrentInstance();
FacesMessage fm = new FacesMessage(msg);
fm.setSeverity(FacesMessage.SEVERITY_ERROR);
context.addMessage(clien_id, fm);
}
ADF full performance monitor
Like other web applications, Oracle ADF applications potentially use a lot of JVM memory. Many times, the root cause of a high memory usage is that application data retrieved from the database into memory is not properly limited; hundreds or thousands of rows (with too many attributes) are fetched and held in ADF BC memory. This can lead to memory over-consumption, very long running JVM garbage collections, a freeze of all current requests or even OutOfMemoryErrors. To make matters worse, these rows and their attributes are frequently retained (passivated and activated) in the session for an unnecessary long period of time. The solution to this problem can be found in reducing the size of sessions by decreasing of the amount of data loaded and held in the session. With a low memory consumption, a more responsive, stable and scalable ADF application can be delivered.
This blog describes one of the new features of the ADF Performance Monitor; a kind of ADF BC memory recorder and analyzer. It detects and warns when too many rows are being fetched (from the database or webservice) and held in ADF BC memory.
ADF BC memory load analyzer of the ADF Performance Monitor
For a selected time range (month, week, day, hour, 5 minute), the tool gives aggregated overviews for each ViewObject instance how many rows have been fetched/loaded into ADF BC memory (ViewObject row cache and entity cache). ViewObjects that frequently fetch hundreds or thousands of rows – and potentially waste memory – can be detected. Individual high fetches/loads can be further analyzed.
For each ViewObject, for a selected time range (month, week, day, e.g.), there are the following overviews:
- The total (sum) of all the ViewObject rows (by ViewObject) that are created in ADF BC memory and fetched from the database. In this overview (screenshot below) ViewObject instances that frequently fetch too many database rows can be detected. The metrics of this example overview is coming from a test server. In this case we can see that ViewObject instance Pagg009ShowAM.GbsVslVO is fetching/retrieving by far the most rows – frequently thousands of database rows. We can see that from mid November 2013 to the end of January 2014 it fetched in total 184.000 database rows (and created 184.000 ViewRowImpl objects). And the highest fetch was 7000 rows in a single HTTP request. This should be a trigger for further investigation.
- The maximum ViewObject rows (by ViewObject) that are fetched from the database and created (cached) in ADF BC memory in a single HTTP request. In general, to avoid memory over-consumption, very long running JVM garbage collections, a freeze of all current requests or even OutOfMemoryErrors, we should not allow ViewObjects to fetch and load more than ±500 rows. All ViewObject instances that are able to fetch and cache more than ±500 rows should be a candidate for further investigation. In this case (see image below) the same ViewObject instance Pagg009ShowAM.GbsVslVO has fetched the most rows of all ViewObjects in a single HTTP request: 7000 rows. The other ViewObjects that have fetched more than 500 rows should also be investigated.
With these two overviews, ViewObject instances that frequently fetch and load too many database rows can be addressed.
The tool can zoom in and analyze the individual high load (fetch) occurrences of a ViewObject (click on the ViewObject instance name). In the detail overview we can analyze when the high load occurrences happened and how many rows were fetched each time:
We can drill down further to the call stack of the HTTP request. It can be useful to analyze, and find out more details about the circumstances of the high load like: What were the bind parameter values of the ViewObject query? Which ViewCriteria were applied (if one was applied)? Did it happen during ApplicationModule activation? Which taskflow was involved ?
With all this detail information, ViewObject instances that frequently waste ADF BC memory can be addressed. For example by adding extra bind parameters, setting a (better) maximum fetchsize or using Range Paging.
Detecting an overload of ViewObject rows
The metrics classes of the ADF Performance Monitor make use of extension points in the ADF framework in order to measure the time every action/step takes in a http request. It makes use of ADF BC framework extension classes. To measure how many rows are fetched from the database and how many ViewObject rows are created and cached, there are several possibilities:
- Invoking the getFetchedRowCount() in the BaseViewObjectImpl after the fetch is complete:
int fetched = viewObjectImpl.getFetchedRowCount();
- Measuring the population of ViewRowImpl objects in the base BaseViewObjectImpl
And counting them in the BaseViewRowImpl. Before a query is executed (again), you should reset the counter. You can do this in the executeForCollection(), the method that is invoked before each database query.
- Overriding the method createRowFromResultSet() and counting them in the BaseViewObjectImpl. This is how the ADF Performance Monitor keeps track of the number of fetched rows and number of ViewRowImplobjects created. Reset the counter before a query is executed (again):
A high load can now be detected in JDevelopers console log. You might want to not log every single row that is fetched but only when you detect a high load.
Wednesday, April 4, 2018
Child record not found in detail af:table then do not save.
Header EoImpl
protected void doDML(int operation, TransactionEvent e) {
System.out.println("***********************");
BindingContext bindingContext = BindingContext.getCurrent();
DCDataControl dc = bindingContext.findDataControl("AppModuleAMDataControl");
AppModuleAMImpl appM = (AppModuleAMImpl)dc.getDataProvider();
System.out.println("********************Vo"+ appM.findViewObject("PiStktrfReqDtl2"));
ViewObject vo = appM.findViewObject("PiStktrfReqDtl2");
System.out.println("********************Vo"+vo);
int stockReqDetailRowCount=vo.getRowCount();
System.out.println("*********Row count is"+stockReqDetailRowCount);
if(stockReqDetailRowCount==0)
// showMessage();
throw new JboException("Child Record not found Please Check...");
else
super.doDML(operation, e);
}
protected void doDML(int operation, TransactionEvent e) {
System.out.println("***********************");
BindingContext bindingContext = BindingContext.getCurrent();
DCDataControl dc = bindingContext.findDataControl("AppModuleAMDataControl");
AppModuleAMImpl appM = (AppModuleAMImpl)dc.getDataProvider();
System.out.println("********************Vo"+ appM.findViewObject("PiStktrfReqDtl2"));
ViewObject vo = appM.findViewObject("PiStktrfReqDtl2");
System.out.println("********************Vo"+vo);
int stockReqDetailRowCount=vo.getRowCount();
System.out.println("*********Row count is"+stockReqDetailRowCount);
if(stockReqDetailRowCount==0)
// showMessage();
throw new JboException("Child Record not found Please Check...");
else
super.doDML(operation, e);
}
Insert a new row at the end in af:table
keep below code at voimpl
import oracle.jbo.Row;
import oracle.jbo.Row;
public void insertRow(Row row){
Row lastRow = this.last();
if (lastRow != null){
int range = this.getRangeIndexOf(lastRow) +1;
this.insertRowAtRangeIndex(range, row);
this.setCurrentRow(row);
}else{
super.insertRow(row);
}
}
Creating new row on pressing “TAB” key in the last cell of Table.
There are three main steps
- First add clientListener and serverListener to last column of ADF table.<af:column sortproperty="#{bindings.EmployeesView1.hints.LastName.name}" sortable="false" headertext="#{bindings.EmployeesView1.hints.LastName.label}" id="c3"> <af:inputtext value="#{row.bindings.LastName.inputValue}" label="#{bindings.EmployeesView1.hints.LastName.label}" required="#{bindings.EmployeesView1.hints.LastName.mandatory}" columns="#{bindings.EmployeesView1.hints.LastName.displayWidth}" maximumlength="#{bindings.EmployeesView1.hints.LastName.precision}" shortdesc="#{bindings.EmployeesView1.hints.LastName.tooltip}" id="it1" autosubmit="true"> <af:clientlistener method="tabkeypressed" type="keyPress"> <af:serverlistener type="tabpress" method="#{pageFlowScope.TestBean.tabPressed}"> <f:validator binding="#{row.bindings.LastName.validator}"> </f:validator></af:serverlistener></af:clientlistener></af:inputtext> </af:column>
- Following java script method is called when user press any key on last table cell’s text field. In java script code we are identifying the TAB key, if user presses “TAB” key then managed bean method is called using server listener.
- function tabkeypressed(evt){
- var _keyCode = evt.getKeyCode();
- var comp = evt.getSource();
- if (_keyCode == AdfKeyStroke.TAB_KEY ){
- AdfCustomEvent.queue(comp, "tabpress",{}, true);
- evt.cancel();
- }
- }
- Managed bean method checks whether current row is the last row or not. If current row is last row of the table, then it will create a new row at the end of the table.
- public void tabPressed(ClientEvent clientEvent) {
- BindingContext bindingctx=BindingContext.getCurrent();
- BindingContainer binding=bindingctx.getCurrentBindingsEntry();
- DCBindingContainer bindingsImpl = (DCBindingContainer) binding;
- DCIteratorBinding dciter = bindingsImpl.findIteratorBinding("EmployeesView1Iterator");
- ViewObject vo=dciter.getViewObject();
- //Return current row index no.
- int index=vo.getCurrentRowIndex()+1;
- //get the last row no.
- long cnt=vo.getEstimatedRowCount();
- if(cnt==index)
- {
- createRow();
- AdfFacesContext.getCurrentInstance().addPartialTarget(emptab);
- }
- }
- public void createRow()
- {
- //Get ViewObject
- BindingContext bindingctx=BindingContext.getCurrent();
- BindingContainer binding=bindingctx.getCurrentBindingsEntry();
- DCBindingContainer bindingsImpl = (DCBindingContainer) binding;
- DCIteratorBinding dciter = bindingsImpl.findIteratorBinding("EmployeesView1Iterator");
- //Get current data RowSetIterator
- RowSetIterator rsi =dciter.getRowSetIterator();
- //Get last Row of current Iterator
- Row lRow = rsi.last();
- //Get index of the last row
- int lrIndex = rsi.getRangeIndexOf(lRow);
- //Create a new row
- Row nRow = rsi.createRow();
- //Initialize that row
- nRow.setNewRowState(Row.STATUS_INITIALIZED);
- //Add row in last of current rowset
- rsi.insertRowAtRangeIndex(lrIndex + 1, nRow);
- //Set newly created row as current row
- rsi.setCurrentRow(nRow);
- }
Subscribe to:
Posts (Atom)