Master Detail Insert/Delete Sample

In the last couple of weeks a question on the OTN JDeveloper & ADF forum about how to insert and delete in a master-detail szenario was asked frequently. There are some threads in the forum talking about this, but apparently no solution which answers all the questions. This post tries to fill in the gap.

Use case
The use case we implement in this blog is as follows: we have a master detail relationship defined by a foreign key in the detail table. We use the REGION and COUNTRIES tables of the HR DB schema. There is a 1..* relationship between the REGION and the COUNTRIES tables. When you look at the REGIONS table only four regions are defined. We want to be able to create a new region and add some new countries into the detail table COUNTRIES before committing the whole transaction. Likewise we want to delete a region together with the countries attached to it, but also a country by itself without deleting a region.

Implementation
The insert part is pretty simple as the ADF framework does it automatically for you. You only have to use the right view objects from the data control and the framework does all the magic of propagating the FK to the child table when you insert a new row into the child table. This even works if you just added a new row to the master without committing it before inserting new child records.
The cascading delete part is not as obvious as the framework offers some help, but delegates the real work to the DB. If the DB knows about the cascading delete it works out OK. However, when you build the business components from the DB tables, the framework does not tell the DB that you want the cascading delete to happen. So without a small change the use case won’t work without us manually deleting all child rows ourselves.

In this blog we build a sample which shows how this use case can be implemented with the help of the DB. In an OTN Harvest post What happens when you choose cascade delete on an association Frank Nimphius talked about what it means if we choose the cascade delete option on an association. Here is a quote from the article:


One of the configuration options in the visual editor is Implement Cascade Delete that is located in the
Relationship menu under the Behavior header. Selecting this option indicates that all detail rows that are
associated with a parent entity should be deleted when the parent entity is deleted.
However, ADF Business Components does not itself perform the cascade delete, but expects a database
constraint to be defined for this. All that the Implement Cascade Delete does is to change the delete
command issued by ADF Business Components to the database.
To quote the “Oracle Fusion Middleware Fusion Developer’s Guide for Oracle Application Development
Framework”

” … When selected, this option allows the composing entity object to be removed unconditionally together with any composed
children entities. If the related Optimize for Database Cascade Delete option is deselected, then the composed entity objects
perform their normal DELETE statement at transaction commit time to make the changes permanent. If the option is
selected, then the composed entities do not perform the DELETE statement on the assumption that the database ON
DELETE CASCADE constraint will handle the deletion of the corresponding rows.

In summary, the article tells us what to do to make the cascading delete work. We need to make the foreign key constraint aware of that by setting it’s delete action to ‘CASCADE’. This we can do from within JDeveloper by using the DB Navigator. Open the HR connection and then open the ‘Tables’ node. Here we select the COUNTRIES table and edit it:

Change FK Constraints on the DB Table COUNTRIES

Change FK Constraints on the DB Table COUNTRIES


Select ‘CASCADE’ in the ‘On Delete’ drop down box in the Foreign Key dialog box:
Set Constraint to CASCADE

Set Constraint to CASCADE


After this change the rest of the use case is just setting up the UI.

Setting up the UI
First we take a look at the ‘Data Controls’ where we see the master detail relationship between the Regions and Countries:

Data Controls

Data Controls


The UI is build in on fragment ‘SchowMasterDetail.jsff’ which consists of a vertical splitter. In the upper part we put the master (Region) as a form and in the bottom part the detail (Countries) as editable table.

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1" xmlns:af="http://xmlns.oracle.com/adf/faces/rich" xmlns:f="http://java.sun.com/jsf/core">
  <af:panelStretchLayout id="psl1">
    <f:facet name="center">
      <af:panelSplitter id="ps1" orientation="vertical" splitterPosition="150">
        <f:facet name="first">
          ...
        </f:facet>
       <f:facet name="second">
         ...
       </f:facet>
      </af:panelSplitter>
      <!-- id="af_one_column_stretched"   -->
    </f:facet>
    <f:facet name="bottom"/>
  </af:panelStretchLayout>
</jsp:root>

To get the master data into the form we drag the Region view object from the data controls on the first splitter facet and drop it as form with submit and navigation buttons. After this we add another panelGroupLayout where we put some additional buttons which we use to create a new region, delete a region, rollback the changes and commit the changes.

For the detail we use the Countries view object from the data controls and drop it as table (editable) on the center facet of a panelStretchLayout which we put on the second facet of the panelSplitter. We mark the table singe selection and sortable. As we did for the regions we add some buttons to the bottom facet which we use to create a new country, delete a country, rollback the changes or commit them. Rollback and commit are for the whole transaction. Even if we click the rollback in the detail part, the whole transaction is rolled back.

Final Page Layout

Final Page Layout


The image above shows the final page layout. Only two things are left to do. We change to the bindings tab of the ShowMasterDetail.jsff and set the ‘ChangeEventPolicy’ for both iterators (Region and Countries) to ‘ppr’. This spares us to update the input fields and the table after each click on one of the navigation buttons. If you are using 11.1.1.7.0 or 11.1.2.x this is the default for newly created iterators. For older versions you have to do it yourself.
Set ChangeEventPolicy to PPR

Set ChangeEventPolicy to PPR

Set ChangeEventPolicy to PPR

Set ChangeEventPolicy to PPR


Running Application
The images below are showing the running sample. We start by verifying that no countries for attached to region id 5 are present, then create a new region with the id 5. Without committing the new region we create some new countries for the fresh created region 5. Finally we commit the transaction and verify that the new data is present in the DB.

Now we delete the new region 5 with all countries created.

The sample was built using JDeveloper 11.1.1.7.0 and uses the HR DB schema. It should be work with JDeveloper 11.1.1.5.0, 11.1.1.6.0 and JDeveloper 11.1.2.3.0 too. You can download the sample from the ADF-EMG Sample Project ‘BlogMasterDetail.zip’

How to Add New Choice to an af:selectOneChoice at Runtime

A question on the JDeveloper and ADF OTN forum asked for help on how to add a new choice to an af:selectOneChoise on the page during runtime. The selectOneChoice is based on is a table in the DB.
This sample shows how to do this using the HR DB schema. The workspace is built using JDev 11.1.1.7.0 but should work without a problem using 11.1.1.4.0 and higher too. You may be asked if you want to migrate, which you should answer with ‘Yes’. The sample can be downloaded using the link provided at the end of this blog.

As this is a real simple data model it only uses the REGIONS table from the HR DB schema. As we want to add new values to the regions table we need to generate entity and view object for the Regions table. We name the VO RegionsLov to make clear that we use this VO as base for a LOV in the UI. To add a new row into this table we implement a public method in the application module which we expose through the client interface of the am. This method isn’t needed as we could simply use createWithParams method from the VO, but the use case asked on the forum did use a method in the application module too.

    public void insertRegion(Integer id, String name) {
        if (id == null || name == null)
            throw new JboException("No Data!");
        Row row = getRegionsLov().createRow();
        row.setAttribute("RegionId", id);
        row.setAttribute("RegionName", name);
        getRegionsLov().insertRow(row);
        // commit is used here only because of the use case from the forum!
        this.getTransaction().commit();
    }

You see that the method uses a commit statement, which I prefer not to do. The reason for this is that you can’t reuse this method in other cases where no commit is allowed because there are other pending changed which you don’t want to commit at the moment. We can remove the commit and call the commit from a bean or directly from a button in the UI to make the method reusable.

We use the VO as dynamic list in the UI so we don’t need to add ViewAccessors or list attributes on the VO. Before we built the UI we add three temporary variables into the variables iterator of the pageDef file. Refer to Creating Variables and Attribute Bindings to Store Values Temporarily in the PageDef for information about how to do this. One variabel ‘RegionId’ (as Integer) is used to store the selection of the LOV we build, the other two ‘newRegionId’ (as Integer) and ‘newRegionName’ (as String) are used to create a new region row in the REGIONS table.
The LOV is built from a af:selectOneChoice which we generate by dragging the RegionsLov’s RegionId attribute onto the page and drop it as SelectOneChoice. The image below shows the binding as dynamik list

Define af:SelectOneChoise

Define af:SelectOneChoise


The whole UI looks like
Final UI

Final UI


Here we see the form with the two inputText components which store their values in temporary pageDef variables ‘newReginId’ and ‘newRegionName’. Here is the full pageDef file for reference:

<?xml version="1.0" encoding="UTF-8" ?>
<pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel" version="11.1.1.64.93" id="StartPageDef" Package="de.hahn.blog.addvaluesoc.view.pageDefs">
  <parameters/>
  <executables>
    <variableIterator id="variables">
      <variable Name="region" Type="java.lang.Integer"/>
      <variable Name="showregion" Type="java.lang.Boolean" DefaultValue="false"/>
      <variable Name="newRegionId" Type="java.lang.Integer"/>
      <variable Name="newRegionName" Type="java.lang.String"/>
    </variableIterator>
    <iterator Binds="RegionsLov" RangeSize="-1" DataControl="BAVSOCAppModuleDataControl" id="RegionsLovIterator"/>
  </executables>
  <bindings>
    <list IterBinding="variables" id="RegionId" DTSupportsMRU="true" StaticList="false" ListIter="RegionsLovIterator" NullValueId="PLEASE_SELECT"
          NullValueFlag="start">
      <AttrNames>
        <Item Value="region"/>
      </AttrNames>
      <ListAttrNames>
        <Item Value="RegionId"/>
      </ListAttrNames>
      <ListDisplayAttrNames>
        <Item Value="RegionName"/>
      </ListDisplayAttrNames>
    </list>
    <attributeValues IterBinding="variables" id="newRegionId1">
      <AttrNames>
        <Item Value="newRegionId"/>
      </AttrNames>
    </attributeValues>
    <attributeValues IterBinding="variables" id="newRegionName1">
      <AttrNames>
        <Item Value="newRegionName"/>
      </AttrNames>
    </attributeValues>
    <methodAction id="insertRegion" InstanceName="BAVSOCAppModuleDataControl.dataProvider" DataControl="BAVSOCAppModuleDataControl" RequiresUpdateModel="true"
                  Action="invokeMethod" MethodName="insertRegion" IsViewObjectMethod="false">
      <NamedData NDName="id" NDValue="" NDType="java.lang.Integer"/>
      <NamedData NDName="name" NDType="java.lang.String"/>
    </methodAction>
  </bindings>
  <ResourceBundle>
    <PropertiesBundle xmlns="http://xmlns.oracle.com/adfm/resourcebundle" PropertiesFile="de.hahn.blog.addvaluesoc.view.BAVSOCViewControllerBundle"/>
  </ResourceBundle>
</pageDefinition>

Now we look at the running application:


Here we see that originally are only four regions present in the selectOneChoice, and we add a new one with the Id=5 and the name ‘aaaaaaaa’ which is inserted with a click on the ‘Insert New Region’ button. The button calls a method in a managed bean

    public void insertRegionListener(ActionEvent actionEvent) {
        // GET A METHOD FROM PAGEDEF AND EXECUTE IT
        // get the binding container
        BindingContainer bindings =
            BindingContext.getCurrent().getCurrentBindingsEntry();
        // get an ADF attributevalue from the ADF page definitions
        AttributeBinding attrId =
            (AttributeBinding)bindings.getControlBinding("newRegionId1");
        Integer id = (Integer)attrId.getInputValue();
        AttributeBinding attrName =
            (AttributeBinding)bindings.getControlBinding("newRegionName1");
        String name = (String)attrName.getInputValue();
        // get an Action or MethodAction
        OperationBinding method = bindings.getOperationBinding("insertRegion");
        if (method == null) {
            FacesMessage msg =
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Method insertRegion not found!",
                                 "");
            FacesContext.getCurrentInstance().addMessage(null, msg);
            return;
        }

        // if there are parameters to set...
        Map paramsMap = method.getParamsMap();
        paramsMap.put("id", id);
        paramsMap.put("name", name);
        // execute the method
        method.execute();
        List errors = method.getErrors();
        if (!errors.isEmpty()) {
            Exception e = (Exception)errors.get(0);
            FacesMessage msg =
                new FacesMessage(FacesMessage.SEVERITY_ERROR, e.getMessage(),
                                 "");
            FacesContext.getCurrentInstance().addMessage(null, msg);
            return;
            // handle errors here errors is a list of exceptions!
        }

        // Get a attribute value of the current row of iterator
        DCBindingContainer dcBindings = (DCBindingContainer)bindings;
        DCIteratorBinding iterBind =
            (DCIteratorBinding)dcBindings.get("RegionsLovIterator");
        iterBind.executeQuery();

        // gat the form for refresh
        UIComponent ui = (UIComponent)actionEvent.getSource();
        ui = ui.getParent();
        ResetUtils.reset(ui);
        attrId.setInputValue(null);
        attrName.setInputValue(null);

        // PPR refresh a jsf component
        AdfFacesContext.getCurrentInstance().addPartialTarget(ui);

    }

The method first gets the entered parameters for the new region id and name, then calls the method to insert the data in the AM (insertRegion) and finally requires the iterator which is used for the selectOneChoice in the UI (RegionsLovIterator).

You can download the sample workspace which was built with JDev 11.1.1.7.0 and which uses the HR schema from the ADFEMG Sample Project BlogAddValueSOC.zip page.

Make Disclosed Row the Current Row when using a Detail Facet of a Table

A question on the OTN JDeveloper & ADF forum asked for help on a use case using a table with an active detail facet. The problem is that when you disclose a row to see the detail, the current row is not changing to the disclosed row.

To make this work we add a RowDisclosureListener where we get the row which should be disclosed and make the row the current row.

The sample, which you cam download using the link provided at the end of the post, uses the HR schema. The master table show the employees and the detail facet is used to show details of the current job the employee has.

Running Application

Running Application


The data model looks like
Data Model

Data Model


The tabel is build by dropping the Employees table onto a page as read only table. The detail facet is build by dropping the JobsDetail as read only form onto the facet. The resulting page code looks like

        <af:table value="#{bindings.Employees.collectionModel}" var="row" rows="#{bindings.Employees.rangeSize}"
                  emptyText="#{bindings.Employees.viewable ? 'No data to display.' : 'Access Denied.'}" fetchSize="#{bindings.Employees.rangeSize}"
                  rowBandingInterval="0" selectedRowKeys="#{bindings.Employees.collectionModel.selectedRow}"
                  selectionListener="#{bindings.Employees.collectionModel.makeCurrent}" rowSelection="single" id="t1"
                  rowDisclosureListener="#{ShowEmployees.rowDiscloseListener}">
...
          <f:facet name="detailStamp">
            <af:panelFormLayout id="pfl1" partialTriggers="::t1">
              <af:panelLabelAndMessage label="#{bindings.JobId.hints.label}" id="plam3">
                <af:outputText value="#{bindings.JobId.inputValue}" id="ot10"/>
              </af:panelLabelAndMessage>
              <af:panelLabelAndMessage label="#{bindings.JobTitle.hints.label}" id="plam1">
                <af:outputText value="#{bindings.JobTitle.inputValue}" id="ot7"/>
              </af:panelLabelAndMessage>
              <af:panelLabelAndMessage label="#{bindings.MinSalary.hints.label}" id="plam2">
                <af:outputText value="#{bindings.MinSalary.inputValue}" id="ot8">
                  <af:convertNumber groupingUsed="false" pattern="#{bindings.MinSalary.format}"/>
                </af:outputText>
              </af:panelLabelAndMessage>
              <af:panelLabelAndMessage label="#{bindings.MaxSalary.hints.label}" id="plam4">
                <af:outputText value="#{bindings.MaxSalary.inputValue}" id="ot9">
                  <af:convertNumber groupingUsed="false" pattern="#{bindings.MaxSalary.format}"/>
                </af:outputText>
              </af:panelLabelAndMessage>
            </af:panelFormLayout>
          </f:facet>

The problem now is, that if we click on the disclose arrow on the left hand side we see the detail information of the current employee row (the master row). The disclosure of a row doesn’t set the current row to the disclosed row.
The solution is to make the disclosed row the current row. For this we add a rowDisclosureListener to the table which points to a method in a bean. The code of hte listener look like

    /**
     * Disclosure event
     * @param rowDisclosureEvent
     */
    public void rowDiscloseListener(RowDisclosureEvent rowDisclosureEvent) {
        RowKeySet addedSet = rowDisclosureEvent.getAddedSet();
        Object object = rowDisclosureEvent.getSource();
        // iterate over the disclosed row (hopefully only one)
        for (Object obj : addedSet) {
            List<Key> rowKeys = (List<Key>)obj;
            // make the disclosed row the current row
            this.makeDisclosedRowCurrent(rowDisclosureEvent,
                                         (Key)rowKeys.get(0));
        }
    }

    /**
     * Synchronizes the table UI component row selection with the
     * selection in the ADF binding layer
     * @param rowDisclosureEvent event object created by the table
     * component upon row selection
     */
    public static void makeDisclosedRowCurrent(RowDisclosureEvent rowDisclosureEvent,
                                               Key key) {
        RichTable _table = (RichTable)rowDisclosureEvent.getSource();
        //the Collection Model is the object that provides the
        //structured data
        //for the table to render
        CollectionModel _tableModel = (CollectionModel)_table.getValue();
        //the ADF object that implements the CollectionModel is
        //JUCtrlHierBinding. It is wrapped by the CollectionModel API
        JUCtrlHierBinding _adfTableBinding =
            (JUCtrlHierBinding)_tableModel.getWrappedData();
        //Acess the ADF iterator binding that is used with
        //ADF table binding
        DCIteratorBinding _tableIteratorBinding =
            _adfTableBinding.getDCIteratorBinding();

        //get the row key from the added rowdisclosure event
        Key _rwKey = key;
        _tableIteratorBinding.setCurrentRowWithKey(_rwKey.toStringFormat(true));
    }

The method rowDiscloseListener is used to get the key of the disclosed row and the method makeDisclosedRowCurrent is used to make the row the current row and synchronise the binding layer to reflect this.

You can download the sample thos the ADFEMG Sample side BlogTableDetail.zip
The sample uses the HR schema and was built with JDev 11.1.1.7.0 but works works with 11.1.1.4.o and higher too.

Using one ViewObject for Global Lookup Data (Part 2)

Based on the other post ‘Using one ViewObject for Global Lookup Data’ I got an other question on how to use this approach in a way, that a LOV is initalized with an area of lookup data before the page in shown to the user.
This can be done, all declarative without the need to write java code e.g. in an onLoad() method. The solution is to use a bounded task flow which initializes the LOV before navigation to the page the LOV is used.
To show this we create a simple navigation model in the adfc-config.xml like

Navigation Model

Navigation Model

‘Generic Lookup’ is used to show how to do this inside a page, where the lookup is presented in a region, the ‘LookupInitPosition’ shows how to preset an area for the lookup data (POSITION in this case) before showing the page in a region too.
Before we go into detail on how to setup the UI we need to add another view object to our data model which we use the acquire the lookup data

VO to get Lookup Data

VO to get Lookup Data


The ‘GeneralLookup’ view object is the same we used in part 1 to get the lookup data of an area, only this time we don’t specify lookup area but a dummy value (‘1’ in this case) for the area. This dummy value is set so that we don’t get any result back. If the ‘GeneralLookup’ view is executed without an area given from the outside, we don’t get any result. Keep this in mind when we are looking at the running sample later on.

Back to the UI. As both use cases uses a region it’s a nice sample how a bounded task flow (btf) can be reused in different use cases. The bounded task flow itself looks like

Navigation Model Bounded Task Flow

Navigation Model Model Bounded Task Flow

Bounded Task Flow to Show preselected Lookup Data

Bounded Task Flow to Show preselected Lookup Data


As you see the bounded task flow uses a method call (ExecuteWithParams) as it’s start activity. A task flow parameter is used to pass the name of the lookup area we want the LOV to initially show.
The name of the input parameter does not really matter, what you have to note down is the value part ‘#{pageFlowScope.selectedType}’ as this is the the variable we use to set the bindType parameter of the method call activity ExecuteWithParams.

Setup of the ExecuteWithParams Method Call

Setup of the ExecuteWithParams Method Call

After executing the query with the new set bindType we navigate to to page to show the result:

Region View1 which shows the LOV with the Preselected Lookup Data

Region View1 which shows the LOV with the Preselected Lookup Data


We see the LOV as af:selectOneChoice which stores the selected value in an attribute from the variable iterator (see Creating Variables and Attribute Bindings to Store Values Temporarily in the PageDef for more info on this). The input text below the LOV can be used to change the area parameter used for the LOV. If we enter e.g. WEEKDAY and click the ‘Refesh’ button, the input value is read and transferred to the parameter (#{pageFlowScope.selectedType}) for the executeWithParameter method via a af:setPropertyListener. This allows to change the LOV on the fly from within the region.
The LOV source is a dynamic list generated from the Generallookup VO as seen in the next image
Setup LOV for af:selectOneChoice

Setup LOV for af:selectOneChoice

After we know how the region (the bounded task flow) works, we can build the GenericLookup.jspx page. This page allows to enter the name of an ares into an input text field and then to refresh the bounded task flow, which we put on the page as region.

The final use case is to navigate to a page with with a preselected lookup area, POSITION in this case. For this we use the button ‘goto Page with init on POSITION’ at the bottom of the page.

You can download the sample workspace which was build JDeveloper 11.1.1.7.0 and using the HR schema from the ADF EMG Samples side BlogStaticVOLov_V3.zip. You can open the workspace using JDev 11.1.1.6.0 without a problem. If you are asked if you like to migrate the workspace to 11.1.1.6.0 answer with Yes.

Installing JDeveloper 11.1.1.7.0 from the Generic Installer Jar on 64bit Windows System

If you have installed JDev 11.1.1.7.0 lately, which I strongly recommend, you may have noticed, that the windows installer jdevstudio11117install.exe still ships with jdk160_24. Please don’t ask why Oracle don’t includes a JDk 1.7, I don’t know.
Well, it’s time to use JDK1.7 on my WIn7x64 system so I loaded hte jdevstudio11117install.jar which is a lot bigger (1.9GB) but comes without a bundeld JDK. As I have already installed JDK 1.7.0_17 on my system I pointed the installation to this jdk when I asked during the installation.
Everything went smooth and i took only a couple of minutes to install JDev and generate the embedded WLS 10.3.5 instance.

However, when I tried to start the embedded WLS instance I got the following error message

*** Using port 7101 ***
r:\jdeveloper\system\system11.1.1.7.40.64.93\DefaultDomain\bin\startWebLogic.cmd
[waiting for the server to complete its initialization...]
.
.
JAVA Memory arguments: -Xms256m -Xmx512m
.
WLS Start Mode=Development
.
CLASSPATH=...
.
PATH=...
.
***************************************************
*  To start WebLogic Server, use a username and   *
*  password assigned to an admin-level user.  For *
*  server administration, use the WebLogic Server *
*  console at http:\\hostname:port\console        *
***************************************************
starting weblogic with Java version:
<strong>Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
Unrecognized option: -jrockit</strong>
Starting WLS with line:
...
Process exited.

Hm, ‘Unrecognized option: -jrockit‘, how’s that? I’m running Sun JDK!
Right at the beginning of the server start we see the command used to start the server (the path may be different on your system)
r:\jdeveloper\system\system11.1.1.7.40.64.93\DefaultDomain\bin\startWebLogic.cmd
A look into this command shell reveals that another command shell script is called
r:\jdeveloper\system\system11.1.1.7.40.64.93\DefaultDomain\bin\setDomainEnv.cmd
In this script we find the problem

...
set BEA_JAVA_HOME=C:\Program Files\Java\jdk1.7.0_17

set SUN_JAVA_HOME=


if "%JAVA_VENDOR%"=="Oracle" (
	set JAVA_HOME=%BEA_JAVA_HOME%
) else (
	if "%JAVA_VENDOR%"=="Sun" (
		set JAVA_HOME=%SUN_JAVA_HOME%
	) else (
		set JAVA_VENDOR=Oracle
		set JAVA_HOME=C:\Program Files\Java\jdk1.7.0_17
	)
)
...

As you see hte BEA_JAVA_HOME is set and if you put an
echo %JAVA_VENDOR%
before the if statement you see that the vendor is null. This sets the JAVA_HOME correct, but sets the JAVA_VENDOR to ‘Oracle’. This then adds the wrong option -jrockit to the command line later on in the startWebLogic.cmd script.

Now that we know that the solution is to make a small change to the
r:\jdeveloper\system\system11.1.1.7.40.64.93\DefaultDomain\bin\setDomainEnv.cmd
script. We only have to set the SUN_JAVA_HOME and set the JAVA_VENDOR to ‘Sun’

set BEA_JAVA_HOME=

set SUN_JAVA_HOME=C:\Program Files\Java\jdk1.7.0_17
set JAVA_VENDOR=Sun

After this change the embedded WLS server starts without a problem.

Using one ViewObject for Global Lookup Data

A user on the OTN JDeveloper & ADF forum asked how to use one ViewObject, which holds lookup data of different areads, as LOV source. This post shows how to do this.

UPDATE:
In part 2 I added a use case which shows how to use a global lookup view object to initialize a LOV component before a page loads and show the selected lookup data.

Before we begin we have to setup the data for the the sample we build to work with. For this we add two tables to the HR schema (or any other schema you have access to). One, GENERALLOOKUP, hols lookup data, which is grouped ba a type attribute.

General Lookup Data

General Lookup Data


As we see the type column is used to group the data into different areas. The task is to use one view object which queries this table as base for model driven LOVs. To show this we need another table which we use to enter values selected by a LOV for the area from the type column.
Test Table and Data

Test Table and Data

BlogGeneralLokup 018

Scripts to create the tables and insert some data into them are provided together with the sample workspace in the file ‘setup_db.sql’. After we setup the table and the data we create entity objects and view objects like we normally do. Once the eo and vo are created, we add a view criteria which we use to select a specific type of lookup data from the GENERALLOOKUP table.

ViewCriteria to Select Lookup Data

ViewCriteria to Select Lookup Data

The view criteria has one bind variable which we later use to distinguish the different groups of lookup data. Now we can setup the lov for the attributes of the LookupTestView view object. We show this for the TitleId attribute:

Setup LOV for  TitleId Attribute

Setup LOV for TitleId Attribute


Create LOV VO

Create LOV VO


BlogGeneralLokup 003 View Accessors
rename the view object to TiltelookupView andshuttle it to the selected area
Select the GeneralLookupView

Select the GeneralLookupView


Click the edit button on the top right
Edit the LOV View

Edit the LOV View


The vital part is that we switch to the ‘View Object’ node and select the view criteria ‘TypeLookupViewCriteria’ and set the bind variable to the desired type. In this case it is ‘TITLE’
BlogGeneralLokup 006 Edit View Accessor_ TitlelookupView

Select ViewCriteria and Bind Variable

Select ViewCriteria and Bind Variable

Once the list source is setup we select the id of the list source (TitlelookupView) as ‘List Attribute’ and set the TitleId as ‘View Attribute’ for the id. Finally select the ‘UI Hint’ tab and shuttle the ‘Data’ attribute to the ‘Selected’ side. The ‘Data’ attribute of the TitlelookupView will then shown in the listbox on the UI.
BlogGeneralLokup 008 Create List of Values

BlogGeneralLokup 009 Create List of Values

Setup LOV for TitleId

Setup LOV for TitleId

This concludes the implementation for the TitleId attribute. The other attributes (GenderId, PositionId and WeekdayId) are done hte same way. Only change the bind variable ‘bindType’ to the type area you are generating the LOV for.

The gallery above shows the running application. You can download the sample workspace which was build JDeveloper 11.1.1.7.0 and using the HR schema from the ADF EMG Samples side BlogStaticVOLov_V2.zip. You can open the workspace using JDev 11.1.1.6.0 without a problem. If you are asked if you like to migrate the workspace to 11.1.1.6.0 answer with Yes.

UPDATE:
In part 2 I added a use case which shows how to use a global lookup view object to initialize a LOV component before a page loads and show the selected lookup data.

JDev 11.1.1.7.0: Table Pagination: Beware of the Layout Container

As you might have noticed, JDeveloper 11.1.1.7.0 brought the pagination feature for tables back. Looks a bit different than the old style, but is available again.
When I tested the paging of table I stumbled upon some interesting stuff. Luc Bors (ADF 11.1.1.7 : The return of the paging table (… and more ….)) and Andrejus Baranoski (ADF 11g PS6 – ADF 10g Table Pagination Feature is Back Finally) posted samples using the new pagination feature. However, when I tried it out at first, the pagination did not show up.

First Try: No Pagination

First Try: No Pagination

I checked the settings

  • scrollPolicy=’page’ (yes, this is a new attribute for the table component)
  • autoHeightRows=’0′

But they were set correct. Then I found the message

falling back to scrolling mode since we need parent component to flow and authHeightRows=0

in my log window and things cleared up.

Log Messages

Log Messages

As Luc wrote in his article, you have to put the table in a layout container in flow mode. This I did not (I read it but did not pay attention at first). To say it again, to make pagination work, the table has to be in a layout container in flow mode. This can e.g. a panelGroupLayout or a showDetailHeader.

If you look into the tag doc of the af:table component, the section

Geometry Management

  • This component can be stretched by a parent layout component that stretches its children, e.g. panelStretchLayout.
  • When stretching this component, the only valid setting for autoHeightRows is “-1” (a value of 0 will be treated as -1 when stretched).
  • When NOT stretched, autoHeightRows=”0″ can be used to size the height to the fetch size, which is similar to dimensionsFrom=”children”. Please refer to ‘autoHeightRows’ attribute for more information.
  • This component does not stretch its children.

If the oracle.adf.view.rich.geometry.DEFAULT_DIMENSIONS context-param is set to “auto” in the project’s web.xml, and the autoHeightRows value is set to 0, or is not set, the AFStretchWidth style class will be rendered for this component.

It’s not described clearly in the doc, but as you have to set autoHeightRows=0 to make pagination work, you can’t put a table in paging mode in a layout container in stretch mode. After changing the page, or better adding a new page with a layout container in scroll mode (here a panelGroupLayout) the pagination showed up:

Table with Pagination

Table with Pagination

You can download the sample from ADF EMG Samples page. The sample uses JDeveloper 11.1.1.7.0 and the HR DB schema.

JDeveloper 11.1.1.7.0 Available

Last Friday the first signs that the long waited for JDeveloper 11.1.1.7.0 will be available soon were found on the web. Today, April 1st, you can download JDeveloper 11.1.1.7.0 from the OTN side.
Now that the Release Notes and What’s New documents are available, I looked at some fixws and new features.
I’m glad to see especially these fixes and new features:

ADF Faces and Data Visualization (DVT)

Skyros Skin: Skyros Skin

    A new look and feel that incorporates current UI visual design trends (flat, rather than dimensional, reduced gradients, reduced borders, light and or white colors with splashes of color). This skin family uses CSS3 for gradients, drop shadows, rounded corners etc. in comparison to the fusion skins that use background images. Making this skin modern, lightweight, and easy to skin.

Pivot Table Enhancements:

    Ability to always display layer headers
    Ability to wrap header labels
    An API to control the percentage of screen real estate allocated to the header region

Table Enhancements:

    Support for freezing the right most columns in a table so that a scroll bar appears on the left side of the frozen columns.

File Upload Enhancements:

    Support chunked file transfer for large file uploads
    Support for multiple file upload using HTML5 UI where available, and non-HTML5 with java applet. Includes a Drag and Drop interface and a progress bar.

ADF Model

Support complex types in service based EOs: Allow attributes of complex types to be exposed in Service-Based EOs.

The next couple of days I’ll spend checking fixes and new features.

Please read the ‘Release Notes’ and ‘What’s new’ documents (linked at the start of the post) for the complete list of enhancements and bug fixes.