28 Feb 2015

LOVs in Oracle MAF

We all love one of the most powerful ADF features lists of values. Using them we can declaratively and easily build pretty complicated functionality in ADF applications. A good thing is that we have a similar approach in Oracle MAF as well. In ADF BC we define LOVs, attribute UI hints, validation  rules, etc. at the Business Service level, basically at the Entity or VO level. In MAF we are able to do the same but at the Data Controls level. This is pretty obvious since who knows what the business service is. It can be whatever in Oracle MAF.
So, in this post I am going to show how we can define and work with LOVs in Oracle MAF.
Let's consider a simple use-case. There is a payment form which looks like this:


An end user selects an account in the drop-down list and the total account balance is going to be used as a default payment amount, however the amount can be changed.
The business model is based on a couple POJO classes:

public class PaymentBO {

    private int accountid;
    private double amount;
    private String note;

and
public class AccountBO {

    private int id;
    private String accountName;
    private double balance;

There is also AccountService class providing a list of available accounts:
public class AccountService {

    private final static AccountService accountService = new AccountService();

    private AccountBO[] accounts = new AccountBO[] {
        new AccountBO(1, "Main Account", 1000.89),
        new AccountBO(2, "Secondary Account", 670.78),
        new AccountBO(3, "Pocket Account", 7876.84),
        new AccountBO(4, "Emergency Account", 7885.80)
    };


    public AccountBO[] getAccounts() {
        return accounts;
    }


    public static synchronized AccountService getInstance() {
        return accountService;
    }

And there is PaymentDC class which is exposed as a data control:
public class PaymentDC {

    private final PaymentBO payment = new PaymentBO();
    private final AccountService accountService = AccountService.getInstance();

    public PaymentBO getPayment() {
        return payment;
    }


    public AccountBO[] getAccounts() {
        return accountService.getAccounts();
    }
}

The DataControl structure looks like this:



In order to be able to define Payment attribute settings such as UI hints, validation rules, LOVs, etc. I am going to click the pencil button and I will have a form which looks pretty similar to what we have in ADF BC:




Those who are familiar with ADF BC will hardly get lost here. So, at the List of Values page we can define a LOV for the accountid attribute:





Having done that, we're able to setup LOV's UI hints, etc. Basically that's it. All we need to do is to drop accountid attribute from that DataControl palette onto a page as a selectOneChoice component.


<amx:selectOneChoice value="#{bindings.accountid.inputValue}"
                     label="#{bindings.accountid.label}" id="soc1">
    <amx:selectItems value="#{bindings.accountid.items}" id="si1"/>
</amx:selectOneChoice>


The framework will do the rest defining the list binding definition in the pageDef file:

 <list IterBinding="paymentIterator" StaticList="false"
        Uses="LOV_accountid" id="accountid" DTSupportsMRU="true"
        SelectItemValueMode="ListObject"/>


But we have to implement somehow setting of the payment amount with the account balance when the account is selected. In ADF we would be able to define multiple attribute mappings in the LOV's definition and that would be the solution. Like this:


But in MAF it doesn't work. Unfortunately.  Only the primary mapping works. So, we're going to do that manually in the PaymentBO.setAccountid  method:

public void setAccountid(int accountid) {
    this.accountid = accountid;

    AccountBO account = AccountService.getInstance().getAccountById(accountid);
    if (account != null) {
        setAmount(account.getBalance());
    }
}

And in the PaymentBO.setAmount method we have to fire a change event in order to get the amount field refreshed on the page:

public void setAmount(double amount) {
    double oldAmount = this.amount;
    this.amount = amount;
    propertyChangeSupport.firePropertyChange("amount", oldAmount, amount);
}


That's it!

The sample application for this post can be downloaded here. It requires JDeveloper 12.1.3 and MAF 2.1.0.