Tuesday, December 29, 2009

EJB and ADF Faces RC: How to Create a SelectOneChoice with Value Bound to an Object Property

There has been a lot of blog post with regards to creating SelectOneChoice in ADF Faces RC but all are bound to a data control based on ADF Business Components . In this post, I will try show you how to create a selectOneChoice component if you want to bound the value to an object property (not just mapping simple data types like String, Long, etc.).
Please see below a demonstrative code snippet being ConversionRate as the object to be edited or created and the CurrencyFrom and CurrencyTo are the object attributes of ConversionRate that will be implemented as SelectOneChoice:
<af:selectOneChoice value="#{bindings.findConversionRateByIdIterator.currentRow.dataProvider.currencyFrom}"
                       label="CurrencyFrom"
                       required="true" id="soc1"
                       autoSubmit="true">
   <f:selectItems value="#{myBackingBean.currencyItems}"
                     id="si1"/>
</af:selectOneChoice>
<af:selectOneChoice value="#{bindings.findConversionRateByIdIterator.currentRow.dataProvider.currencyTo}"
                          label="CurrencyTo"
                          required="true" id="soc2"
                          autoSubmit="true">
     <f:selectItems value="#{myBackingBean.currencyItems}"
                       id="si2"/>
</af:selectOneChoice>
The trick on this is the "currentRow.dataProvider" thing. Replace the "findConversionRateByIdIterator" above with your own applicable iterator.

Please see below a dummy backing bean class to enforce illustration of the idea:
package blogspot.soadev.view.backing;

import java.util.ArrayList;
import java.util.List;
import oracle.binding.BindingContainer;
import oracle.binding.OperationBinding;
import javax.faces.model.SelectItem;

public class MyBackingBean {
  private List<SelectItem> currencyItems;
  public List<SelectItem> getCurrencyItems() {
      if (currencyItems == null) {
          List<Currency> currencyList = getCurrencyList();
          currencyItems = new ArrayList<SelectItem>();
          for (Currency currency : currencyList) {
              currencyItems.add(new SelectItem(currency, currency.getCode()));
          }
      }
      return currencyItems;
  }
    public List<Currency> getCurrencyList() {
        //findAllCurrencies is methodAction binding
        return (List<Currency>)getOperationBinding("findAllCurrencies").execute();
    }

  public OperationBinding getOperationBinding(String operation) {
    BindingContainer bindings =
      (BindingContainer)JSFUtils.resolveExpression("#{bindings}");
    return bindings.getOperationBinding(operation);
  }
}
class Currency {
  private String code;
  private String description;

  public void setCode(String code) {
    this.code = code;
  }

  public String getCode() {
    return code;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public String getDescription() {
    return description;
  }
}
class ConversionRate{
  private Currency currencyFrom;
  private Currency currencyTo;
  private Double rate;

  public void setCurrencyFrom(Currency currencyFrom) {
    this.currencyFrom = currencyFrom;
  }

  public Currency getCurrencyFrom() {
    return currencyFrom;
  }

  public void setCurrencyTo(Currency currencyTo) {
    this.currencyTo = currencyTo;
  }

  public Currency getCurrencyTo() {
    return currencyTo;
  }

  public void setRate(Double rate) {
    this.rate = rate;
  }

  public Double getRate() {
    return rate;
  }
}

Saturday, December 26, 2009

EJB Security: Logging the user that invokes a session bean method

If you have a requirement to log the user who created or updated a certain record. You can do so by getting the CallerPrincipal object in the SessionContext of an EJB session bean. The SessionContext can be injected in a session bean using the @Resource annotation. Please see below a sample session bean with an injected SessionContext plus the call to get the CallerPrincipal object:
package oracle;

import java.util.List;
import javax.annotation.Resource;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

@Stateless(name = "HRFacade", mappedName = "HR_EJB_JPA_App-EJBModel-HRFacade")
@Remote
@Local
public class HRFacadeBean implements HRFacade, HRFacadeLocal {
    @PersistenceContext(unitName="EJBModel")
    private EntityManager em;
    @Resource
    private SessionContext context;

    public HRFacadeBean() {
    }
    public Employee mergeEmployee(Employee employee) {
        String username = context.getCallerPrincipal().getName();
        employee.setUpdatedBy(username);
        return em.merge(employee);
    }
...
}