ADF

How to populate View Object rows programmatically, without SQL?

I think that first thing beginner ADF developer gets familiar with is bussiness components (BC) and in particular View Objects. Thats the base and main axis of ADF BC. Most common usage is definately Entity or SQL Query based View Objects. But when facing a real world requirements, its not as rare case to build BC on some different kind of data sources. It can be a Ref Cursor out of pl/sql function, POJO, in memory array, Java properties file or even some API i.e. one for Oracle BPM Worklist. Lets build here one tiny sample just to get understanding how things work. Will create programmatic View Object based on simple ArrayList which we just hardcode in the same View Object. Of course in real world you’d need to get data out of somewhere else. But this article is not about this, its about how to create View Object itself.

Assuming that you’re fine with creating ADF Application, Application Modules (AM)View Objects(VO) and adding them to AM, creating .jspx pages, displaying data in there via components you need. In this application we already have set up all of this, will just pay attention to programmatic View Object. Will create as simple as possible EmployeesView with just 3 attributes: id, name, surname. Here are the initial steps we will go through:

  • Create a View Object. Please select Programmatic when you’re asked for a type:

  • Make sure all attributes added to a view object are set as always updatable:

  • Generate EmployeesViewImpl.java and EmployeesViewRowImpl.java source files:

So we did an initial preparation for configuring programmatic View Object. Now lets go to the essence. And it is overriding of EmployeesViewImpl class we just generated. Oracle documentation says, that for fully functioning programmatic VO we need to override these methods:

  • create()

This method is called when the view object instance is created and can be used to initialize any state required by the programmatic view object. At a minimum, this overridden method will contain the following lines to ensure the programmatic view object has no trace of a SQL query related to it:

  • executeQueryForCollection()

This method is called whenever the view object’s query needs to be executed (or re-executed).

  • hasNextForCollection()

This method is called to support the hasNext() method on the row set iterator for a row set created from this view object. Your implementation returns true if you have not yet exhausted the rows to retrieve from your programmatic data source.

  • createRowFromResultSet()

This method is called to populate each row of “fetched” data. Your implementation will call createNewRowForCollection() to create a new blank row and then populateAttributeForRow() to populate each attribute of data for the row.

  • getQueryHitCount()

This method is called to support the getEstimatedRowCount() method. Your implementation returns a count, or estimated count, of the number of rows that will be retrieved by the programmatic view object’s query.

  • protected void releaseUserDataForCollection()

Your code can store and retrieve a user data context object with each row set. This method is called to allow you to release any resources that may be associated with a row set that is being closed.

Lets do what we’re asked for. Here are all of those methods one by one overriden in our sample:

  • create()
/**
* Overriden view object's method.
*/
protected void create() {
super.create();

// Wipe out all traces of a query for this VO
getViewDef().setQuery(null);
getViewDef().setSelectClause(null);
setQuery(null);
}

  • executeQueryForCollection()
/**
* executeQueryForCollection - for custom java data source support.
*/
@Override
protected void executeQueryForCollection(Object qc, Object[] params, int noUserParams) {

Map<String, String> employeeData = new HashMap<String, String>();
employeeList = new ArrayList<Map<String, String>>();

employeeData.put("id", "1");
employeeData.put("name", "John");
employeeData.put("surname", "Miller");
employeeList.add(employeeData);

employeeData = new HashMap<String, String>();
employeeData.put("id", "2");
employeeData.put("name", "Peter");
employeeData.put("surname", "Braun");
employeeList.add(employeeData);

setFetchPos(qc, 0);

super.executeQueryForCollection(qc, params, noUserParams);
}

  • hasNextForCollection()
/**
* hasNextForCollection - for custom java data source support.
*/
@Override
protected boolean hasNextForCollection(Object qc) {

boolean hasNext = getFetchPos(qc) < employeeList.size();

return hasNext;
}

  • createRowFromResultSet()
/**
* createRowFromResultSet - for custom java data source support.
*/
@Override
protected ViewRowImpl createRowFromResultSet(Object qc, ResultSet resultSet) {

int pos = getFetchPos(qc);

EmployeesViewRowImpl empRow = (EmployeesViewRowImpl) createNewRowForCollection(qc);

empRow.setId(employeeList.get(pos).get("id"));
empRow.setName(employeeList.get(pos).get("name"));
empRow.setSurname(employeeList.get(pos).get("surname"));

setFetchPos(qc, pos + 1);

return empRow;

}

  • getQueryHitCount()
/**
* getQueryHitCount - for custom java data source support.
*/
@Override
public long getQueryHitCount(ViewRowSetImpl viewRowSet) {
long value = super.getQueryHitCount(viewRowSet);
return value;
}

  • protected void releaseUserDataForCollection()
protected void releaseUserDataForCollection(Object qc, Object rs) {
ResultSet udc = (ResultSet) getUserDataForCollection(qc);
if (udc != null) {
try {
udc.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
super.releaseUserDataForCollection(qc, rs);
}

  • Also additionally you might miss here definition of  employeeList, which is private class attribute:
private ArrayList<Map<String, String>> employeeList;

  • And couple of helper methods for setting and retrieving fetching position of view rowset:
private void setFetchPos(Object rowset, int pos) {
if (pos == employeeList.size()) {
setFetchCompleteForCollection(rowset, true);
}
setUserDataForCollection(rowset, new Integer(pos));
}

private int getFetchPos(Object rowset) {
return ((Integer) getUserDataForCollection(rowset)).intValue();
}

Complete sample application can be downloaded here.

If you want to test it live, just deploy to local integrated server and open URL //localhost:7101/ProgrammaticVODemo/faces/index.jspx  to check records displayed.

For more and official information on how to leverage benefits of programmatic view object, please refer to Oracle Documentation.

ADF Version 12.2.1.0.0


Advertisement

8 thoughts on “How to populate View Object rows programmatically, without SQL?

  1. Dear Danas,
    thanks, for your helpful post , but what about view criteria in the programmatic VO , should i override any method to work ?

    1. Hi Amaged!
      I’m very happy that this post was helpful for you!
      View criteria in programmatic VO is configured the same way as in i.e. SQL Query based one. Just in View Criteria configuration window need to set “Query execution mode” to “In Memory”. All attributes in this kind of view object are Transient, thus the only way to deal with them is in application server memory.

  2. Hi Danas,

    Your post is really helpful. I wanted to created an LOV from the programmatic View Object Data. So to test it, I have downloaded your sample application and created another programmatic view object in it with a transient attribute and added a List Of Value for that transient attribute from your Programmatic view object(added as view access in the new Programmatic View). I see the Data in the LOV but when I try to search with any specific value in the LOV pop up I get the below exception.

    java.lang.ClassCastException: java.lang.Integer cannot be cast to java.sql.ResultSet
    at model.EmployeesViewImpl.releaseUserDataForCollection(EmployeesViewImpl.java:120)
    at oracle.jbo.server.QueryCollection.closeCollection(QueryCollection.java:607)
    at oracle.jbo.server.QueryCollection.closeCollection(QueryCollection.java:593)
    at oracle.jbo.server.ViewObjectImpl.clearQueryCollectionCache(ViewObjectImpl.java:10259)
    at oracle.jbo.server.ViewRowSetImpl.initQueryCollection(ViewRowSetImpl.java:950)
    at oracle.jbo.server.ViewRowSetImpl.execute(ViewRowSetImpl.java:1309)
    at oracle.jbo.server.ViewRowSetImpl.execute(ViewRowSetImpl.java:1220)
    at oracle.jbo.server.ViewRowSetImpl.executeQueryForMasters(ViewRowSetImpl.java:1716)
    at oracle.jbo.server.ViewRowSetImpl.executeQueryForMode(ViewRowSetImpl.java:1600)
    at oracle.jbo.server.ViewRowSetImpl.executeQuery(ViewRowSetImpl.java:1580)
    at oracle.adf.model.bc4j.DCJboDataControl.executeIteratorBinding(DCJboDataControl.java:1458)
    at oracle.adf.model.binding.DCIteratorBinding.doExecuteQuery(DCIteratorBinding.java:2532)
    at oracle.adf.model.binding.DCIteratorBinding.executeQuery(DCIteratorBinding.java:2493)
    at oracle.jbo.uicli.binding.JUSearchBindingCustomizer.applyAndExecuteViewCriteria(JUSearchBindingCustomizer.java:675)
    at oracle.jbo.uicli.binding.JUSearchBindingCustomizer.applyAndExecuteViewCriteria(JUSearchBindingCustomizer.java:781)
    at oracle.adfinternal.view.faces.model.binding.FacesCtrlSearchBinding.performQuery(FacesCtrlSearchBinding.java:828)
    at oracle.adfinternal.view.faces.model.binding.FacesCtrlLOVBinding$ListOfValuesModelImpl.performQuery(FacesCtrlLOVBinding.java:2234)
    at oracle.adfinternal.view.faces.renderkit.rich.SimpleInputListOfValuesRendererBase$InternalLOVQueryListener.processQuery(SimpleInputListOfValuesRendererBase.java:2133)
    at oracle.adf.view.rich.event.QueryEvent.processListener(QueryEvent.java:68)
    at org.apache.myfaces.trinidad.component.UIXComponentBase.broadcast(UIXComponentBase.java:1127)
    at oracle.adf.view.rich.component.UIXQuery.broadcast(UIXQuery.java:74)
    at oracle.adf.view.rich.component.rich.RichQuery.broadcast(RichQuery.java:463)
    at org.apache.myfaces.trinidad.component.UIXComponent.broadcastInContext(UIXComponent.java:364)
    at oracle.adf.view.rich.event.ProxyEvent.broadcastWrappedEvent(ProxyEvent.java:72)
    at oracle.adf.view.rich.component.fragment.UIXRegion._handleProxyEvent(UIXRegion.java:933)
    at oracle.adf.view.rich.component.fragment.UIXRegion.broadcast(UIXRegion.java:117)
    at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:790)
    at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1282)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._invokeApplication(LifecycleImpl.java:1243)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._executeInvokeApplication(LifecycleImpl.java:686)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._executePhase(LifecycleImpl.java:364)
    at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:227)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:650)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:286)
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:260)
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:137)
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:350)
    at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:25)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)
    at oracle.adf.model.servlet.ADFBindingFilter.doFilter(ADFBindingFilter.java:207)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)
    at oracle.adfinternal.view.faces.webapp.rich.RegistrationFilter.doFilter(RegistrationFilter.java:105)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:529)
    at oracle.adfinternal.view.faces.activedata.AdsFilter.doFilter(AdsFilter.java:60)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:529)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl._doFilterImpl(TrinidadFilterImpl.java:354)
    at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl.doFilter(TrinidadFilterImpl.java:232)
    at org.apache.myfaces.trinidad.webapp.TrinidadFilter.doFilter(TrinidadFilter.java:92)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)
    at oracle.security.jps.ee.http.JpsAbsFilter$3.run(JpsAbsFilter.java:172)
    at java.security.AccessController.doPrivileged(Native Method)
    at oracle.security.jps.util.JpsSubject.doAsPrivileged(JpsSubject.java:315)
    at oracle.security.jps.ee.util.JpsPlatformUtil.runJaasMode(JpsPlatformUtil.java:650)
    at oracle.security.jps.ee.http.JpsAbsFilter.runJaasMode(JpsAbsFilter.java:110)
    at oracle.security.jps.ee.http.JpsAbsFilter.doFilterInternal(JpsAbsFilter.java:273)
    at oracle.security.jps.ee.http.JpsAbsFilter.doFilter(JpsAbsFilter.java:147)
    at oracle.security.jps.ee.http.JpsFilter.doFilter(JpsFilter.java:94)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)
    at oracle.dms.servlet.DMSServletFilter.doFilter(DMSServletFilter.java:248)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)
    at weblogic.servlet.internal.RequestEventsFilter.doFilter(RequestEventsFilter.java:32)
    at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3701)
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3667)
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:326)
    at weblogic.security.service.SecurityManager.runAsForUserCode(SecurityManager.java:197)
    at weblogic.servlet.provider.WlsSecurityProvider.runAsForUserCode(WlsSecurityProvider.java:203)
    at weblogic.servlet.provider.WlsSubjectHandle.run(WlsSubjectHandle.java:71)
    at weblogic.servlet.internal.WebAppServletContext.doSecuredExecute(WebAppServletContext.java:2443)
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2291)
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2269)
    at weblogic.servlet.internal.ServletRequestImpl.runInternal(ServletRequestImpl.java:1703)
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1663)
    at weblogic.servlet.provider.ContainerSupportProviderImpl$WlsRequestExecutor.run(ContainerSupportProviderImpl.java:272)
    at weblogic.invocation.ComponentInvocationContextManager._runAs(ComponentInvocationContextManager.java:352)
    at weblogic.invocation.ComponentInvocationContextManager.runAs(ComponentInvocationContextManager.java:337)
    at weblogic.work.LivePartitionUtility.doRunWorkUnderContext(LivePartitionUtility.java:57)
    at weblogic.work.PartitionUtility.runWorkUnderContext(PartitionUtility.java:41)
    at weblogic.work.SelfTuningWorkManagerImpl.runWorkUnderContext(SelfTuningWorkManagerImpl.java:644)
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:415)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:355)

    Please help me resolve this issue. Thanks In Advance !

    Thanks,
    Poorni

    1. Hi Poorni,

      I’m really happy that this post was helpful for you! Could you please send me back an extended app, so I can check it out and try to find a cause for this error.

      Kind Regards,
      Danas

      1. Hi Danas,

        Thank you so much for the quick response. I just found that I was getting this error from the below code in the EmployeesViewImpl.

        protected void releaseUserDataForCollection(Object qc, Object rs) {

        ResultSet udc = (ResultSet) getUserDataForCollection(qc);

        if (udc != null) {

        try {

        udc.close();

        } catch (SQLException e) {

        e.printStackTrace();

        }

        }

        super.releaseUserDataForCollection(qc, rs);

        }

        I though I might not need to override this for my functionality so when I remove this overridden code form the view object I do not get any issue and it worked without any issue. May I know the advantage of overriding this method? Or Disadvantage of not overriding it? It will help me understand the framework better.

        Thanks,
        Poorni

        1. Hi Poorni,

          actually you are right. In this particular sample, overriding of releaseUserDataForCollection is not really necessary, because we actually have nothing to release. My sample is a bit simplified as I use “employeeList” for storing a rowset. As indicated in the documentation, “setUserDataForCollection()” should be used to store user rowset. Afterwards it needs to be released using “releaseUserDataForCollection”. As we do not store anything in this sample, have nothing to release using provided means. Thats probably a reason why wrong object type is returned and type casting fails. Please check documentation for usage of “setUserDataForCollection()” if you would like to.

          Kind Regards,
          Danas

    1. Hi!
      I would take one of two options. It depends on what websevice you want to utilize. If it is a remote Oracle ADF Fusion Business Service, which data you want to use in current BC model, then it is offered special built in solution for that. You can create service-based entity objects and use them as normal ADF BC. Wen creating new entity object, can choose data source between “Database Schema Object” and “Service Interface”. Choose the latter one. Please check Fusion Developer’s Guide for more details (//docs.oracle.com/applications/falcm12/OADEE/GUID-CEBD5295-7C8C-4A9F-B251-F12FFE4A5E44.htm#OADEV60353).
      Although if you need to leverage some other kind of service, you can always implement necessary logic, which invokes webservice and fetch data through View Object a similar way as in this programmatic VO sample.

      Kind Regards,
      Danas

Leave a Reply

Your email address will not be published.