Tag Archives: ADF BC

Retrieve the Old Value of an Attribute in the View Object

Sometimes we need to access the old value of an attribute, this is explained well by Chris Muir in ADF Insider video Retrieving the previous value of an ADF BC attribute. This can be done by using getPostedAttribute method in the EntityImpl class, this method gets the value originally read value for  a specific attribute from the database and it has a protected access modifier. But what if you want to access the old value in the View object and you don’t have a control on the Entity object; such as if the entity objects are deployed as ADF library jar and you don’t have any privilege to access or modify these entities; is it possible to access the old value from the view object? in this post I will show how do this in an easy way. Suppose we want to access the old value of the department name attribute in the DepartmentsView  which is based on Departments table in HR schema.

  1.  Create a transient attribute, OldDepartmentName in the DepartmentsView.
  2. Generate the DepartmentsViewRowImpl class, check the include accessors check box, this will add getter/setter methods for all the attributes of this view object. by default the getDepartmentName method will look like this: 
    /**
    * Gets the attribute value for the calculated attribute OldDepartmentName.
    * @return the OldDepartmentName
    */
    public String getOldDepartmentName() {
    return (String) getAttributeInternal(OLDDEPARTMENTNAME);
    }
  3. Override the getOldDepartmentName() method to:
        /**
         * Gets the attribute value for the calculated attribute OldDepartmentName.
         * @return the OldDepartmentName
         */
        public String getOldDepartmentName() {
            byte status = EntityImpl.STATUS_UNMODIFIED;
            return (String) getAttributeInternal(DEPARTMENTNAME, status);
        }

Now, the getOldDepartmentName() will return the old value from the database.

Advertisements

Leave a comment

Filed under ADF

How to Solve oracle.jbo.ConfigException: JBO-33001

Environment (JDeveloper, ADF BC, ADF Faces)

When you work with large application which contains more than one Model/one ViewController projects, you need to set the project dependency between the model and the view controller project., failing to do this you may face this exception.

oracle.jbo.ConfigException: JBO-33001: Configuration file /model/common/bc4j.xcfg is not found in the classpath.

To solve the problem, double click the viewController project to open project properties dialog, and select the the Dependencies node  and click the Edit Dependecies icon to add a dependency on the build output path or on one or more deployment archives.

Hope this will help someone faced the same problem.

3 Comments

Filed under ADF

How to make some LOV items non-selectable

Environment (JDeveloper 11.1.2.0.0,hr schema)

Lately we have a requirement to make some list of values (LOV) items non selectable. As an example suppose that the list of departments should show all departments but some of them mus be disabled or non-selectable as shown below.

LOV with some items being disabled

In this post I will show how to build this kind of LOVs. This example is based on hr schema, mainly on EMPLOYEES and DEPARTMENTS table.  Our goal is to create LOV for the DepartmentId attribute in Employees view but the departments: Administration, Marketing, Purchasing, and Human Resources should be disabled and non selectable.  I will assume that you have already built the business component for this example. The implemantation steps are:

  1. Right click on your page and select Go to page Definition from the menu.
  2. If the page definition file opens in the source view, select the Overview tab at the bottom of the editor. and click the green plus icon  to create a control binding as shown below.create control binding
  3. After click the green plus icon the Insert Item window will be shown, select the tree item and click OK.

    select tree binding from insert item window

  4. After you select the tree binding, the Create Tree Binding window will be shown. Click the Add button to create a new Root Data Source reference or select from a list of existing iterators.The root data source provides the list data and should point to a View Object that you created for the data lookup. Don’t use any View Object that you use for data input within your application. In our case I select DepartmentsView1 to be the root data source.

    select root data source from the data controls

  5. Still the Create Tree Binding window opened, click add rule (green plus icon) and choose the AddRule menu option. This creates a rule entry for the top-level View Object of the selected root data source.

    add rule menu option

  6. Still also in the Create Tree Binding window, move both DepartmentId and DepartmentName to the Display attribute area. we need the DepartmentId for the list value and the DepartmentName to be the display value.

    select display attributes

  7. Now return back to the page and open it it the Jdeveloper visual editor.
  8. From the data controls panel, drag and drop the departmentId attribute from the EmployeesView1 as selectOneChoice component. Press OK and do not do any configuration. Note that Jdeveloper shows an error message Indicates that a list data source is not selected, so we are enforced to select a data source and we will delete it later.

    Edit lis binding window

  9. Now the page source for the DepartmentId attribute will be something like this:
    <af:selectOneChoice value="#{bindings.DepartmentId.inputValue}" label="#{bindings.DepartmentId.label}"
    required="#{bindings.DepartmentId.hints.mandatory}"
    shortDesc="#{bindings.DepartmentId.hints.tooltip}" id="soc1">
    <f:selectItems value="#{bindings.DepartmentId.items}" id="si1"/>
    </af:selectOneChoice>
  10. Delete <f:selectItems> tag  inside <af:selectOneChoice> tag. The page source for the DepartmentId attribute should be:
    <af:selectOneChoice value="#{bindings.DepartmentId.inputValue}" label="#{bindings.DepartmentId.label}"
    required="#{bindings.DepartmentId.hints.mandatory}"
    shortDesc="#{bindings.DepartmentId.hints.tooltip}" id="soc1"/>

    You can also delete the f:selectItems child component from the structure window.

  11. From the structure window, select the af:selectOneChoice and Insert inside af:selectOneChoice |ADF Faces | For Each from the right mouse context menu as shown below.

    insert foreach component

  12. Select the af:forEach component and open the Property Inspector. Click the arrow icon next to the Items property and select the tree binding rangeSet method entry.The returned Expression Language expression should look like this: #{bindings.
    DepartmentsView1.rangeSet}. And set the var attribute to descriptive name. The Var property defines the name for the variable that at runtime is used to populate the list. In this example I chose list as a name.
  13. Now our DepartmentId attribute looks like:
     <af:selectOneChoice value="#{bindings.DepartmentId.inputValue}" label="#{bindings.DepartmentId.label}"
    required="#{bindings.DepartmentId.hints.mandatory}"
    shortDesc="#{bindings.DepartmentId.hints.tooltip}" id="soc1">
    <af:forEach items="#{bindings.DepartmentsView1.rangeSet}" var="list"/>
    </af:selectOneChoice>
  14. Select the af:forEach component in the Structure Window and choose Insert inside af:forEach | ADF Faces  and choose Select Item component as shown below.

    insert <af:selectItem> component

  15. For the af:selectItem component set the Value attribute to #{list.DepartmentId}, Label attribute to #{list.DepartmentName}, and Disabled attribute to #{list.DepartmentId eq 10 or list.DepartmentId eq 20 or list.DepartmentId eq 30 or list.DepartmentId eq 40} which represents the Ids of the departments we want to be disabled.
  16. With this configuration applied, the DepartmentId attribute look like this:
    <af:selectOneChoice value="#{bindings.DepartmentId.inputValue}" label="#{bindings.DepartmentId.label}"
    required="#{bindings.DepartmentId.hints.mandatory}"
    shortDesc="#{bindings.DepartmentId.hints.tooltip}" id="soc1">
    <af:forEach items="#{bindings.DepartmentsView1.rangeSet}" var="list">
    <af:selectItem label="#{list.DepartmentName}" id="si1" value="#{list.DepartmentId}"
    disabled="#{list.DepartmentId eq 10 or list.DepartmentId eq 20 or list.DepartmentId eq 30 or list.DepartmentId eq 40}"/>
    </af:forEach>
    </af:selectOneChoice>
  17. Run your page.

download the sample workspace:MakeSomeLOVItemsNonSelectable.rar

Please change the file extension to .zip or .rar after download.

 

Reference: Oracle Fusion Developer Guide Building Rich Internet Applications with Oracle ADF Business Components and Oracle ADF Faces. Frank Nimphius,Lynn Munsinger.

6 Comments

Filed under ADF

Using comma separated string as a bind variable for SQL query with IN clause

Environment (JDeveloper 11.1.2.0.0, hr schema)

Bind variables are place holders in the SQL string whose value  can be easily changed at runtime without altering the query itself. Since the query text doesn’t change from execution to execution, the database can efficiently reuse the same parsed statement each time (parse once and execute many times). But how can we define a bind variable for IN clause, as an example suppose that we want to pass a comma-separated string of department IDs and execute the query based on our IN clause, and here is the query we wish to execute look like:

select * from departments where department_id IN (:comma-separated-list)

Fortunately, I have found how to do this based on  Steve Muench’s example #126.Using Comma-Separated String Bind for Variable IN List and in this post I am only repeating what Steve has shown before for the sake of sharing. Our goal is to pass a comma-separated string of department IDs at run time and execute our query.

To support bind variable IN clause we need to add the function below to our schema, this function accepts a comma-separated string argument and returns a NUM_TABLE as its result and this allows us to make our bind variable of String type.

CREATE TYPE num_table AS TABLE OF NUMBER;
/
CREATE OR REPLACE FUNCTION in_number_list (p_in_list  IN  VARCHAR2)
RETURN num_table
AS
l_tab   num_table := num_table();
l_text  VARCHAR2(32767) := p_in_list || ',';
l_idx   NUMBER;
BEGIN
LOOP
l_idx := INSTR(l_text, ',');
EXIT WHEN NVL(l_idx, 0) = 0;
l_tab.extend;
l_tab(l_tab.last) := to_number(TRIM(SUBSTR(l_text, 1, l_idx - 1)));
l_text := SUBSTR(l_text, l_idx + 1);
END LOOP;
RETURN l_tab;
END;
/

our DepartmentsView should look like this

SELECT Departments.DEPARTMENT_ID,
Departments.DEPARTMENT_NAME,
Departments.MANAGER_ID,
Departments.LOCATION_ID
FROM DEPARTMENTS Departments
WHERE DEPARTMENT_ID IN (SELECT * FROM TABLE( CAST ( in_number_list(:CommaSeparatedListOfDeptId) as num_table)))

where CommaSeparatedListOfDeptId is a bind variable of type String.

DepartmentsView

you can test the view using the ADF Model Tester and pass a comma-separated string of departments IDs as shown below:

Oracle ADF Model Tester

2 Comments

Filed under ADF

Control row updatability – part 2

Environment (JDeveloper 11.1.2.0.0, ADF BC, ADF Faces)

In the previous post, I have shown how to control the row updatability based on some conditions. Another popular use case for row updatability is making the row or some attributes within the row only updatable while the row status is new, but after being successfully committed to the database they should become read-only. In this post I will show how to implement this use case in declarative and programmatic ways.

  • Declarative method:

The Updatable property controls that is available for each attribute within the entity and view objects has a While New option, we can set this property for single, multiple, or all attributes as shown below.

Updatable Property

 

  • Programmatic method:

we can override isAttributeUpdateable method in the EntityImpl class. If we want the entire row to be updatable while it is  new then override  isAttributeUpdateable method as shown below:

  public boolean isAttributeUpdateable(int i) {
        if (getEntityState()!=STATUS_NEW )
            return false;
        else
            return super.isAttributeUpdateable(i);
    }

If we want single or many attributes to be updatable while the row is new, then override  isAttributeUpdateable method as shown below:

public boolean isAttributeUpdateable(int i) {
        /**
         * ID is the attributeEnum.
         * you can add attributesEnum as required
         * by your use case
         */
        if (getEntityState()!=STATUS_NEW && i== ID)
            return false;
        else
            return super.isAttributeUpdateable(i);
    }

 

see also: Control row updatability – part 1.

Leave a comment

Filed under ADF

Control row updatability – part 1

Environment (JDeveloper 11.1.2.0.0, ADF BC, ADF Faces)

Sometimes developers want to make an entire row as read only based on some conditions, As an example assume that you have an application that allows users to apply for something, once the application is approved they are not allowed to modify any attribute instead they can only see their application, this can be done by setting the read only property for each attribute from the property inspector. However, doing this is a headache approach especially if you want to repeat this in many pages and your row contains many attributes.

To implement such similar case in effective approach, we can override the isAttributeUpdateable method either in the EntityImpl class or in the ViewRowImpl class. If you want your row to be non updatable regardless of the view object being used, then override the isAttributeUpdateable method in the EntityImpl class otherwise override the method in your ViewRowImpl class.

The steps required to do this are, (assumed we need to override the isAttributeUpdateable method in EntityImpl class).

  1. generate your custom EntityImpl class.
  2. Assumed that your EntityImpl class is opened in Jdeveloper main window, click on the source menu, then select Override methods  as shown below.

    Override isAttributeUpdateable method

  3. The Override methods window will open, select the isAttributeUpdateable method and click OK as shown below.

    Select isAttributeUpdateable method

  4. Now override your method based on your condition as shown below:

    public boolean isAttributeUpdateable(int i) {
//you can add your condition here
     //in this case Flag attribute indicates whether
    //an application is approved or not
if (this.getFlag().equals(“Y”))
return false;
else
return super.isAttributeUpdateable(i);
}


see also:  Control row updatability – part 2.

Leave a comment

Filed under ADF

How to control the location of the new row in af:table

Environment (JDeveloper 11.1.2.0.0, ADF BC, ADF Faces, hr schema)

When we add a new row in af:table,the default behavior is that the new row is added before the current row. Sometimes we may need to change this behavior. In this post I will show how we can add new row at different locations within our table, and automatically scrolling to that new row.

This post is based on hr schema (EMPLOYEES table) and assumed that you have already built your BC. The button used to add a new row has its PartialSubmit property set to true, and the table has its PartialTrigger property references the button’s id, also our table should have its DisplayRow property set to selected, the table binding in the managed bean is empTable (setEmpTable(RichTable empTable), getEmpTable()).

  1. To add a new row at the first location on the table use this method:   
    public String addRowAtFirst() {
    // Add event code here…
    CollectionModel tableModel = (CollectionModel)getEmpTable().getValue();
    JUCtrlHierBinding adfModel = (JUCtrlHierBinding)tableModel.getWrappedData();
    DCIteratorBinding dciter = adfModel.getDCIteratorBinding();
    NavigatableRowIterator nav=dciter.getNavigatableRowIterator();
    Row newRow = nav.createRow();
    newRow.setNewRowState(Row.STATUS_INITIALIZED);
    nav.insertRowAtRangeIndex(0, newRow);        dciter.setCurrentRowWithKey(newRow.getKey().toStringFormat(true));
    return null;
    }
  2. To add a new row at the end of the table use this method:   
    public String addRowAtLast() {
    // Add event code here…
    CollectionModel tableModel = (CollectionModel)getEmpTable().getValue();
    JUCtrlHierBinding adfModel = (JUCtrlHierBinding)tableModel.getWrappedData();
    DCIteratorBinding dciter = adfModel.getDCIteratorBinding();
    NavigatableRowIterator nav=dciter.getNavigatableRowIterator();
    Row newRow = nav.createRow();
    newRow.setNewRowState(Row.STATUS_INITIALIZED);
    Row lastRow = nav.last();
    int lastRowIndex = nav.getRangeIndexOf(lastRow);
    nav.insertRowAtRangeIndex(lastRowIndex+1, newRow);
    dciter.setCurrentRowWithKey(newRow.getKey().toStringFormat(true));
    return null;
    }
  3. To add a new row before the current selected row (default behavior) use this method:   
    public String addRowBefore() {
    // Add event code here…
    CollectionModel tableModel = (CollectionModel)getEmpTable().getValue();
    JUCtrlHierBinding adfModel = (JUCtrlHierBinding)tableModel.getWrappedData();
    DCIteratorBinding dciter = adfModel.getDCIteratorBinding();
    NavigatableRowIterator nav=dciter.getNavigatableRowIterator();
    Row newRow = nav.createRow();
    newRow.setNewRowState(Row.STATUS_INITIALIZED);
    nav.insertRow(newRow);        dciter.setCurrentRowWithKey(newRow.getKey().toStringFormat(true));
    return null;
    }
  4. To add a new row after the current selected row use this method:   
    public String addRowAfter() {
    // Add event code here…
    CollectionModel tableModel = (CollectionModel)getEmpTable().getValue();
    JUCtrlHierBinding adfModel = (JUCtrlHierBinding)tableModel.getWrappedData();
    DCIteratorBinding dciter = adfModel.getDCIteratorBinding();
    NavigatableRowIterator nav=dciter.getNavigatableRowIterator();
    Row newRow = nav.createRow();
    newRow.setNewRowState(Row.STATUS_INITIALIZED);
    Row currentRow = nav.getCurrentRow();
    int currentRowIndex = nav.getRangeIndexOf(currentRow);
    nav.insertRowAtRangeIndex(currentRowIndex+1, newRow);
    dciter.setCurrentRowWithKey(newRow.getKey().toStringFormat(true));
    return null;
    }

7 Comments

Filed under ADF