Wednesday, June 30, 2010

Decorate UI with view row Attribute's User Interface hints

This post discusses the possibility of using custom view row attribute hints to decorate your view layer. For example, let us take an Employee table, the use case requirement is to display red icon in a column if the salary is greater than 10000, green icon for all other cases. Please see the below screen shot for reference.



Apparently there are multiple ways to achieve this. The approach I followed here is through custom view row attribute hints implementation. The idea is inspired by an earlier post from Steve.

A glance at the implementation

Implementation is very simple, Override ViewRowAttrHintsImpl::getHint(...) by sub classing ViewRowAttrHintsImpl. Please note that ViewRowAttrHintsImpl::getHint(..) will get invoked whenever the binding layer identifies any custom hints in the EL.

The below implementation overrides the default behavior of getHint(...) to return different icons based on the salary, for the custom hint 'statusIcon'.

Map iconMap = new HashMap<String, String>() {
  {
    put("LowSalIcon", "images/lowSalIcon.gif");
    put("HighSalIcon", "images/highSalIcon.gif");

  }
};

@Override
public String getHint(LocaleContext locale, String sHintName) {

if ("statusIcon".equals(sHintName)) {
    Number salary = (Number)getViewRow().getAttribute("Salary");

    if (salary != null && salary.getValue() > 10000)
    return iconMap.get("HighSalIcon");
    else
    return iconMap.get("LowSalIcon");
}
return super.getHint(locale, sHintName);
}

You can wire this custom ViewRowAttrHintsImpl to a ViewRowImpl by overriding
ViewRowImpl::createViewRowAttrHints(AttributeDefImpl attrDef)

@Override
protected ViewRowAttrHintsImpl createViewRowAttrHints(AttributeDefImpl attrDef) {
return new EmployeesViewRowAttrHintsImpl(attrDef, this);
}

Now, you may need to refer this custom hint(statusIcon) from the UI using EL binding. The below jsf snippet shows how this is done when you use table.

<af:column sortProperty="Status" sortable="false"
     headerText="#{bindings.EmployeesView11.hints.Status.label}"
     id="c7">
<af:image source="#{row.bindings.Status.hints['statusIcon']}"
      id="ai1"/>
</af:column>

How does it work?

While rendering each status column for a table, EL #{row.bindings.Status.hints['statusIcon']} trigger EmployeesViewRowAttrHintsImpl::getHint() method, which in turn return the desired icon.

If you use form, then use below EL binding to refer the custom hint

<af:image source="#{bindings.Status.hints.statusIcon}" id="i2" shortDesc="status"/>

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]

Learn More ...

There are many more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/10/oracle-adf-real-world-developers-guide.html

Monday, June 28, 2010

Style your application in your own way !

Look and feel of your application can be further improved/customized using the Oracle ADF Faces skins and component style attributes. To learn more about this, please refer Chapter 20 Customizing the Appearance Using Styles and Skins from Web User Interface Developer's Guide

Customizing the Style Properties of a Component

Sometimes you may need to customize display 'style' of a specific set of UI components based on various business conditions. Conventional approach is to add 'inlineStyle' to decorate the components of choice. However this approach has it's own drawbacks like high maintenance cost, increased page size, highly error prone(if the same style needs to repeat across multiple pages) etc.

A better approach is to extend the skin that you want to customize and override the style properties as per the use case requirement. Advantage with this approach is that skinning information is specified in one place for an entire application.

A Simple Case Study

Let me take you through a very simple example. Here, the use case requirement is to display the mandatory field labels in 'bold' on a data capture form. Apparently, solution is to customize the css style properties of the UI components. 'Skinning' framework let you to do this job without much effort. Steps are detailed in the Web User Interface Developer's Guide.

In a nutshell, here we are extending the existing skin family by overriding 'Component Selectors' of choice. The below style in the custom css file overrides the 'Label'(Pseudo-element) for an inputText component. As stated earlier,there are set of 'Style Selectors' available for each component which you can override on need basis using a custom css file.

af|inputText::label {
font-weight: bold;
}

Next step is to configure the 'custom skin' in trinidad-skins.xml and wire the css file to this custom skin. Steps are well detailed in Web User Interface Developer's Guide

In our above css sample, property specified for label gets applied to all instances of inputText component. This may not be the desired behavior in all cases. If you need to apply this style only for a specific instances of inputText, then define a style class with standard selector(s) as shown below
.CriticalInputLabelStyle af|inputText::label {
font-weight: bold;
}

Next step is wiring this style class with UI component. This is done by setting the styleClass attribute of the component to the desired style class.
For e.g: the below sample applies CriticalInputLabelStyle to a inputText component. Please note that you can use EL expressions for the styleClass attribute to conditionally set style attributes
<af:inputText value="#{bindings.EmployeeId.inputValue}"
label="#{bindings.EmployeeId.hints.label}" ...
styleClass="#{bindings.EmployeeId.hints.mandatory?'CriticalInputLabelStyle':''}/>

A glance at Run-time Coordination

Below diagram illustrates how the css style definition, skinning meta files and the Renderer coordinates to render the UI components. [Click on the diagram to zoom in]



You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]
This sample illustrates the above example. Run test.jspx, you may notice that the labels for all mandatory fields are displayed in 'bold' on the form.

Wednesday, June 23, 2010

My application throws error after enabling jbo.doconnectionpooling = true !

Recently, a few of the developers reported saying that their application started misbehaving after setting jbo.doconnectionpooling = true. Interestingly, in most of the cases, root cause was one and same - incorrect usage of EntityImpl::postChanges(TransactionEvent e). This method posts changed data to database, and these changes would be only visible within the same transaction associated with current 'Connection' instance. If you are building fusion web application, please don't call this method unless the transaction is getting committed within the same service request. Please note that database transaction is associated with Connection that you are using. If you turn on connection pooling, there is no guarantee that same connection would be available to serve your future service requests (unless you use the reserved release mode for the ApplicationModule).

To learn more on the topic, please go through the following topics from Fusion Developer's Guide for Oracle Application Development Framework
1.41.3.2 What You May Need to Know About Database User State and jbo.doconnectionpooling = true
2.40.11 Keeping Pending Changes in the Middle Tier

Thursday, June 17, 2010

Enabling multiple selection on <af:table>

A common mistake while enabling multiple selection for a data bound table is to leave the default values for attributes(generated while creating the table in a single selection mode) selectedRowKeys and selectionListener as is. This is wrong, these parameters will override the multiple selection that user makes. So you may need to remove them.

To enable multiple select capabilities on a <af:table>,
1. Set rowSelection="multiple"
2. Remove selectedRowKeys and selectionListener attributes(if any)

This is well documented in Fusion Developer's Guide for Oracle Application Development Framework. Please see Section 23.5, "Providing Multiselect Capabilities"

Wednesday, June 16, 2010

Model driven approach for building Dynamic UI

One of the great feature of ADF Rich Client is that support for building User Interfaces on the fly. These dynamic components are smart enough to read the binding metadata and render themselves on the fly. Please read this topic 22.7 Using a Dynamic Form to Determine Data to Display at Runtime, to learn more about this feature. When we talk about the dynamism provided by the ADF Rich Client, story is incomplete without referring support from the ADF BC (business service) layer. You can create dynamic EntityObject, ViewObject and wire them to UI components declaratively, without much effort. In this post, I'm discussing some common 'dynamic UI' based use case requirements and their solutions using ADF.

Case 1: Dynamic UI Table built using dynamic ViewObject(database table and attribute definitions change for each invocation)

Use case requirement: UI needs to be populated from different database tables, based on various business conditions. Number of displayed attributes may vary based on source database table.

Solution : Solution is pretty straight forward. Let us start from the business service layer and then move towards UI layer.

Business Service Layer

You can make use of ApplicationModule::createViewObjectFromQueryStmt(java.lang.String voName, java.lang.String sqlStatement) to define dynamic ViewObjects using the query supplied by the run time.

Binding Layer

Next step is to wire this dynamic ViewObject with UI. Define the necessary binding in your page definition file. You may need to do it manually as we are creating the ViewObject dynamically.

Sample page definition is shown below.
 <executables>
    <variableIterator id="variables"/>
    <iterator Binds="DynamicQueryVO" DataControl="AppModuleDataControl"
              id="DynamicVOIterator"/>
  </executables>
  <bindings>
    <tree IterBinding="DynamicVOIterator" id="DynamicVO">
      <nodeDefinition Name="Dummy"></nodeDefinition>
    </tree>
  </bindings>

UI Layer

For building dynamic UI, either you can use <af:table> along with <af:foreach> to populate table on the fly, or simply leave the job to <dynamic:table> component. Let the component do the job for you. If you need to display the data in a dynamic parameter form, you can use <dynamic:form>

Dynamic components differ from standard components in that all the binding metadata is created at run time. This dynamic building of the bindings allows you set display information using control hints on a view object instead of configuring the information in the Edit Form Fields dialog as you drop the control onto the page

Table populated using <af:foreach> is shown below
 <af:table rows="#{bindings.DynamicVO.rangeSize}"
    fetchSize="#{bindings.DynamicVO.rangeSize}"
    emptyText="#{bindings.DynamicVO.viewable ? 'No data to display.' : 'Access Denied.'}"
    var="row" rowBandingInterval="0"
    value="#{bindings.DynamicVO.collectionModel}"
    selectedRowKeys="#{bindings.DynamicVO.collectionModel.selectedRow}"
    selectionListener="#{bindings.DynamicVO.collectionModel.makeCurrent}"
    rowSelection="single" id="t1">
    <af:forEach items="#{bindings.DynamicVOIterator.attributeDefs}"
        var="def">
      <af:column headerText="#{def.name}" sortable="true"
         sortProperty="#{def.name}" id="c1">
    <af:outputText value="#{row[def.name]}" id="ot1"/>
      </af:column>
    </af:forEach>
  </af:table>
 
Using dynamic:table to display dynamic contents is shown below.
<dynamic:table value="#{bindings.DynamicVOIterator}" id="t3"/>

Case 2: Dynamic UI Table built using ViewObject with dynamic query(Only database table changes, attribute definitions/column types may remain same)

Use case requirement: UI needs to be populated from different database tables, but attribute definition remains same. In other words, only the table changes, number of columns and types remain same.

Solution :

Business Service Layer

Here you just need to swap only the query part of the ViewObject. The attribute definitions remains same for all cases. You can use ViewObject::setQuery(java.lang.String query) to set Sets the user-defined query.

Building UI and the binding this with ViewObject remains same as for the normal implementation.

Case 3: Updatable Dynamic UI Table built using Dynamic EntityObject and ViewObject

Use case requirement: Needs to build an updatable UI based on the database table and attributes which are decided at run time.

Solution : This is a bit tricky situation. As the table is updatable, there should be an EntityObject to post the changes back to database.

Business Service Layer

Solution is to build EntityObject and corresponding ViewObject dynamically based on the metadata supplied by the run time.(Thanks to Steve who shared a sample on similar topic)

Below given sample code builds EntityObjects and corresponding ViewObject on the fly.
EntityDefImpl newEntity = new EntityDefImpl(DYNAMIC_EO);
newEntity.setSource("EMPLOYEES");
AttributeDefImpl newAttrDef1 =
newEntity.addAttribute("EmployeeId", "EMPLOYEE_ID", Number.class,
true, false, true);
ViewDefImpl newView = new ViewDefImpl(DYNAMIC_VO);
newView.addEntityUsage("e", DYNAMIC_EO, false, false);
newView.addAllEntityAttributes("e");
newView.setFetchSize((short)30);
newView.setSelectClauseFlags(ViewDefImpl.CLAUSE_GENERATE_RT);
newView.setWhereClauseFlags(ViewDefImpl.CLAUSE_GENERATE_RT);
newView.setFromClauseFlags(ViewDefImpl.CLAUSE_GENERATE_RT);
newView.resolveDefObject();
newView.registerDefObject();

Binding Layer

'UI Wiring' part is same as discussed under Case 1.

UI Layer

Same as discussed under Case 1.

Conclusion

ADF offers a library of dynamic components which may help you to build dynamic UI without much effort. You may need to choose the right implementation strategy based on your use case requirement.

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]

How to run this sample?

Run the main.jspx. Main page display menu(link) for each case that we discussed here. You can select Department/Employee from the drop down list and then opt for one of the three cases by clicking the corresponding links. This takes you to a result page where data is rendered in a tabular form. This UI is generated on the fly based on the item selected from the drop down.

Learn More ...
There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html

Monday, June 14, 2010

Accessing Resource Bundles from a ViewObject

There were couple of threads in ADF BC discussion forums asking for APIs to access associated resource bundle from a ViewObject/EntityObject class. One possibility is to use standard java.util.ResourceBundle API. Another interesting approach is to make use of the oracle.jbo.common.StringManager APIs used by the ADF BC layer. This is a wrapper over standard java ResourceBundle class.

The below method is based on the second approach. This help you to retrieve the value for a key from the resource bundle associated with a ViewObject.

    public String getLocalizedValue(String key) {

        ResourceBundleDef resourceDef = this.getResourceBundleDef();
        Locale locale = this.getApplicationModule().getSession().getLocale();
        String retVal =
            StringManager.getLocalizedStringFromResourceDef(resourceDef, key,
                                                            false);
        return retVal;
    }

Where can I see the reference for the 'ResourceBundle' in a ViewObject?

<ResourceBundle> element in the ViewObject's XML definition references the associated resource bundle file.
<ViewObject ....>
......
 <ResourceBundle>
    <PropertiesBundle
      PropertiesFile="model.ModelBundle"/>
  </ResourceBundle>
</ViewObject>

You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]

This sample tries to initialize the DepartmentName with a value from the resource bundle that is associated with Department ViewObject. You can see that 'DepartmentsViewRowImpl' java file contains the above mentioned getLocalizedValue(...) method. This method is referred through groovy expression adf.object.getLocalizedValue("DEFULT_DEPT_NAME") specified against DepartmentName in the DepartmentsView.


Learn More ...

There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html

Thursday, June 10, 2010

Create row on a clickToEdit table

Generally developers use 'createInsert' operations associated with the iterator binding to insert a new row. Works perfectly! However, when you use the same technique on a clickToEdit table to create new rows, all goes well, but the newly create record does not become the 'active row'. So the end user can by pass the validation and can create multiple records without key in the mandatory fields for the newly created ones, by clicking the 'Create' button multiple times.

A possible work around solution for this scenario is to customize the record creation, and programatically set the ActiveRowKey, as shown below.

    public void createAction(ActionEvent actevnt) {
        BindingContext bc = BindingContext.getCurrent();
        DCBindingContainer dcb =
            (DCBindingContainer)bc.getCurrentBindingsEntry();
        OperationBinding op = dcb.getOperationBinding("createDept");
        Row row = (Row)op.execute();
        if (op.getErrors().size() == 0) {
            ArrayList lst = new ArrayList(1);
            lst.add(row.getKey());
            getDataTable().setActiveRowKey(lst);
        }
    }
You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS2 + HR Schema]

JBO-27023 Failed to validate all rows

Have you ever experience weird error reporting as shown below, while trying to throw some meaningful validation error from your business methods?
Instead of the desired error, UI reports a generic error saying
JBO-27023 : “Failed to validate all rows”.
What goes wrong?
Take a look at your manged bean where you have the code to invoke methods from ApplicationModule(service layer). Your code may look like as shown below, where you are getting instance of ApplicationModule and invoking methods directly on it.This is not the recommended approach, as you are by passing binding layer. Suggested approach is to let the binding layer to do this job as shown under 'Right Implementation'

Wrong Implementation

    public String someAction() {
        BindingContext bc = BindingContext.getCurrent();
        DCDataControl dc = bc.findDataControl(dataControlName);
        if ((dc != null) && dc instanceof DCJboDataControl) {
            ApplicationModuleImpl amImpl =
                (ApplicationModuleImpl)dc.getDataProvider();
            amImpl.doSomething();
        
        }
        return "success"
    }

Right Implementation

Expose the ApplicationModule method to client and define a methodAction binding for the same, then use the ADF binding api to do the job.

       public String someAction() {
        BindingContainer bindings = getBindings();
        OperationBinding ob = bindings.getOperationBinding("doSomething");
        Object result = ob.execute();
        if (!ob.getErrors().isEmpty()) {
            return "error";
        }
        return "success";
    }

Advantages
1. This gives clear separation between tiers/layers of your application
2. Ensures both binding layer and service layer are in synch.
3. Provides uniform error handling


Learn More ...

There are a lot more points like this. If  you are curious to learn the internals of the ADF Business Components and ADF Binding Layer,  the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html