BTW. Today is Bloomsday - James Joyce abù
This sample uses JDev 11g and ORCL DB11g
In this simple scenario I will detail how to auto refresh a pie chart based on the following query. We will then amend the query where clause to exclude a particular department.
--------------------------------------------------------
SELECT sum(Emp.sal) SalaryTotal,
Dept.deptno,
Dept.dname
FROM Emp, Dept
WHERE Emp.deptno = Dept.deptno
GROUP BY Dept.Dname, Dept.Deptno
--------------------------------------------------------
Pre-requisite on the DB Side
in SQLPLUS --> conn system/manager
grant change notification to scott;
Step 1 - Creating the Model
Create a new Fusion Web Application (ADF) in JDev 11g
In the Model Project - Create new ADF Business Components --> Business Components from Tables
Create a connection to SCOTT's schema on your 11g DB and create Entity Objects based on the tables - Dept & Emp
Create the ViewObjects -
Accept the defaults on the following pages.
Create a new ViewObject for the Chart
Enter the following query on the next page-
SELECT sum(Emp.sal) SalaryTotal,
Dept.deptno,
Dept.dname
FROM Emp, Dept
WHERE Emp.deptno = Dept.deptno
GROUP BY Dept.Dname, Dept.Deptno
Accept defaults on the following steps.
At step 7 - select checkbox - Generate View Object Class: SalByDeptViewImpl
At Step 8 - select checkbox to add the new view to the Application Module
For the new view - Set auto-refresh property = true
Copy and paste the following code into the ...impl class you generated earlier
(after the constructor)
long lastRequery = 0;
public long getLastRequery() {
return lastRequery;
}
@Override
protected void bindParametersForCollection(QueryCollection queryCollection,
Object[] object,
PreparedStatement preparedStatement) throws SQLException {
super.bindParametersForCollection(queryCollection, object, preparedStatement);
if (queryCollection != null) {
lastRequery = System.currentTimeMillis();
}
System.out.println("Re-execute "+(queryCollection == null?"count ":"")+"query for VO "+getName());
}
@Override
protected void processDatabaseChangeNotification(QueryCollection queryCollection) {
lastRequery = System.currentTimeMillis();
super.processDatabaseChangeNotification(queryCollection);
}
}
We have just done the following -
We have created a long value lastRequery
We have overridden the following methods –
-bindParametersForCollection
-processDatabaseChangeNotification
The long value represents the last time the query was executed or it has handled a database change notification event. The value of this long has been exposed so the client can reference it as a custom method, see the getLastRequery() method
bindParametersForCollection() and processDatabaseChangeNotification() update this flag.
Expose the getLastRequery() method via the client interface
Step 2 - Creating the UI
Create a new JSF page via the faces-config.xml (graphical mode)
Double-click on the image to create the page, selecting auto-creation of backing bean.
You are now in the visual editor.
-Drag and Drop a Poll control onto the page.
-Drag and Drop SalByDeptView as a Graph --> Pie Chart onto the page
-Drag and Drop getLastRequery()as a method somewhere on the page
-Edit the jspx source and comment out the button you just dropped as we only need it's binding.
-Go to the pagedef file's overview.
-Click on the SalByDeptView iterator binding.
- In the Property Inspector, change the rangeSize to 100
- Edit the page by selecting the graph component in the structure pane
In the Property Inspector set the ContentDelivery flag to "immediate".
Now we need to poll on lastRequery()
So add the following method to the end of the page's backing bean.
public void onPollTimerExpired(PollEvent pollEvent) {
Long lastRequery = (Long)AdfFacesContext.getCurrentInstance().getViewScope().get("lastRequery");
Long lastRequeryFromVO = (Long)BindingContext.getCurrent().getCurrentBindingsEntry().getOperationBinding("getLastRequery").execute();
System.out.println("Timer expired: lastRequery = "+lastRequery+", lastRequeryFromVO = "+lastRequeryFromVO);
if (lastRequery == null (!lastRequery.equals(lastRequeryFromVO))) {
AdfFacesContext.getCurrentInstance().getViewScope().put("lastRequery",lastRequeryFromVO);
AdfFacesContext.getCurrentInstance().addPartialTarget(getPieGraph1());
System.out.println("Data requeried in VO. PPR'ing the pie chart");
}
}
-Select the Poll operation in the structure window
-- Set the Id to pollTimer
-- Select onPollTimerExpired() in the PollListener propety
-- Set the Interval property to 2000
The onPollTimerExpired poll listener event handler invokes a method action binding to get the lastRequery() long value. It stores this value in the view scope. If it notices that the value has changed, then it PPR's the pie chart.
- In the DataBindings.cpx file, for the "AppModuleDataControl" data control usage, set the configuration to use the "AppModuleShared" configuration. This configuration is automatically created for you by ADF design time, along with the "AppModuleLocal" configuration. Auto-refresh view objects only work when they are in a shared AM.
Step 3 - Test
Run the page from the faces-config.xml diagrammer
Open a cmd window and start sqlplus as scott
Insert a new emp with a large salary e.g.
insert into emp values (
8881,
'Jim',
null,
null,
sysdate,
9999,
100,
30);
commit;
The pie chart will be updated automatically.
Now we will amend the WHERE clause to ignore Department 10.
Step 4 - Dynamically Changing the WHERE clause
To avoid getting an ORA-29983
ORA-29983: Unsupported query for Continuous Query Notification
Cause: The query cannot be registered for Continuous Query Notification.
Action: The query has some constructs that make it incompatible with Continous Query Notification like synonyms or views. Please check the documentation for complete list.
we must deactivate the default use of inline views by calling setNestedSelectForFullSql()
in the create() method of the ...viewImpl class.
Open SalByDeptViewImpl.
We must override the create method so Menu --> Source --> Override Methods.
Select the create() method
Add the following after the line super.create();
this.setNestedSelectForFullSql(false);
We will now add a method to amend the WHERE clause to ignore Department 10.
public void excludeDept10(){
ViewObject vo = this.getViewObject();
// get the original query
String query = vo.getQuery();
System.out.println("VO query is = " + query);
// let's find the WHERE clause
int startOfWhere = query.indexOf("WHERE");
int startOfGroupBy = query.indexOf("GROUP BY");
String whereClause = query.substring(startOfWhere, startOfGroupBy);
System.out.println("Original WHERE Clause = " + whereClause);
// amend the WHERE clause to exclude Dept 10
whereClause = whereClause + " and Dept.deptno > 10 ";
String newQuery = query.substring(0, startOfWhere-1);
newQuery = newQuery + whereClause;
System.out.println("New Query with WHERE = "+ newQuery);
newQuery = newQuery + query.substring(startOfGroupBy, query.length());
System.out.println("New Query with Group BY = "+ newQuery);
this.setQuery(newQuery);
vo.executeQuery();
}
I'm sure there's a much more elegant way on doing this --)
- Expose this method (as we did getLastRequery()) via the client interface
- Refresh the DataControl
- Drop the method as an ADF button on the page
- re-test
Press the button to exclude Dept 10
- Enter a new Emp with a large salary
Tuesday, June 16, 2009
Subscribe to:
Post Comments (Atom)
6 comments:
Thanks, this is the same solution I am hunting for the last two days. I got the auto refresh on for table working (insert and updates), I am still on the hunt for auto-refresh on text boxes. Can you guide me to that.
Thx
hi,
I try to do the same stuff,
but I want an Application Module Root which contains the Application Module which contains the VO where there is the method processDatabaseChangeNotification.
I have trying all the configuration possible of AppModuleRoot and AppModuleChild: Shared/Local, Local/Shared and even Local/Local ... but nothing works ...
Can you tell me if possible, and if so ... how?
thanks!
Niall,
Could you possiblt email me the .jpr project for this example? I've had problems getting i to work in JDev 11.1.1.2 and would like to see your examample. Thanks you.
Matt Orsie
Matthew.Orsie@oracle.com
Hi,
Thanks for the solution, but facing similar problem. A scenario of the viewobject updation/insertion happening with notification to AppModule, is there any such method ?
Hi...
Thank you very much for this blog its very helpful to me....
Hi Sir, where can i find the getPieGraph1()?
it prompts me that the method does not exist.
here's the line of code where the method is called.
AdfFacesContext.getCurrentInstance().addPartialTarget(getPieGraph1());
Hoping for your fast reply.
Thank you.
Post a Comment