Sunday, November 30, 2014

Update VO data programatically

Suppose there is a requirement to search for employees based on certain criteria and then add a bonus to their salaries. Let's say the UI for this includes an employee search, an input text box for entering the bonus amount and a button that should add the bonus to the salaries and update the VO.




Here is one way to achieve this:
- Create a method in AMImpl which updates salary for all the rows in currrent VO row set, and expose this method in AM client interface
public void updateSalary(double bonusPct)
{
 RowSetIterator empRow = getEmployeeView1().createRowSetIterator(null);
 EmployeeViewRowImpl currentRow = new EmployeeViewRowImpl();
 double currentSalary = 0;
 while (empRow.hasNext())
 {
  currentRow = (EmployeeViewRowImpl) empRow.next();
  currentSalary = currentRow.getSalary().doubleValue();
  currentRow.setSalary(new oracle.jbo.domain.Number(currentSalary + (currentSalary * bonusPct/100)));        
 }
 getDBTransaction().commit();
}
- Add the AM method in page bindings
- On button action listener, pass the bonus value from input box as parameter to AM method and execute it
public void addBonus(ActionEvent actionEvent)
{
 BindingContainer bc =
   BindingContext.getCurrent().getCurrentBindingsEntry();
 OperationBinding op = bc.getOperationBinding("updateSalary");
 op.getParamsMap().put("bonusPct", getBonus()); //getBonus() gets the entered bonus value
 op.execute();
}
Now, when you click Add Bonus button, updateSalary will be called and the bonus will be added to the salary of employess.



<< A Request >>
  Please contribute in making this world a better place to live by adopting a pet from your nearest pet shelter (btw cats are my favourite :-) )
<< Thank You >>

Thursday, November 20, 2014

Authenticating Users using OPSS API in ADF

OPSS is the underlying security platform that provides security to ADF. In some cases it is required to access OPSS API programmatically. Here is the code snippets for authenticating users using OPSS API :
 

import oracle.security.idm.IMException;
import oracle.security.idm.IdentityStore;
import oracle.security.idm.User;
import oracle.security.idm.UserManager;
import oracle.security.jps.JpsContext;
import oracle.security.jps.JpsContextFactory;
import oracle.security.jps.service.idstore.IdentityStoreService;

public class OpssApiExample
{
  public Boolean isUserAuthenticated(String username, String password) 
  {
    Boolean isAuthenticated = Boolean.FALSE;
    try
    {
      JpsContextFactory ctxf = JpsContextFactory.getContextFactory();
      JpsContext ctx = ctxf.getContext();
      IdentityStoreService storeService =
        ctx.getServiceInstance(IdentityStoreService.class);
      IdentityStore idStore = storeService.getIdmStore();
      UserManager userManager = idStore.getUserManager();
      User authUser =null;
      try
      {
        authUser =
          userManager.authenticateUser(username, password.toCharArray());
        isAuthenticated = Boolean.TRUE;
      }
      catch (IMException ime)
      {        
        //Could not authenticate
        ime.printStackTrace(); //Print the authentication error
      }
    }
    catch (Exception exp)
    {
      exp.printStackTrace();
    }   
    return isAuthenticated;
  }
  
}




Monday, November 17, 2014

Show status indicator for long running method calls

ADF status indicator provides a way to notify users of a long running process on the page, but does not serve the purpose if the long running process starts before the page gets loaded. For example, there is a task flow that has a method call as its default activity. This method calls a SOAP service and hence takes a good amount of time to complete its execution. The next activity on the task flow is a web page, which only gets loaded when the method call is completed. So, if we add a status indicator on the page, it will not consider the execution time before the loading of page and also there is no way to directly use status indicator on top of a method call.


To notify users of a long running process in such scenarios, replace the method call activity on task flow with a view activity. This view activity will represent a page, which will execute the method call on page load event and will use status indicator to notify the user.


<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <f:view>
    <af:document id="d1">
      <af:messages id="m1"/>
<!-- Calling method on page load -->
      <af:serverListener type="onloadEvent"
                         method="#{backingBeanScope.initBean.callMethod}"/>
      <af:clientListener type="load" method="triggerOnLoad"/>
      <af:resource type="javascript">
        function triggerOnLoad(event)
        {
          AdfCustomEvent.queue(event.getSource(), "onloadEvent", {},false);
          return true;
        }
      </af:resource>
      <af:form id="f1">
<!-- Displaying status indicator in the middle of the page -->
        <af:panelStretchLayout id="psl1" startWidth="33%" endWidth="33%"
                                   topHeight="33%" bottomHeight="33%">
          <f:facet name="bottom"/>
          <f:facet name="center">
            <af:panelGroupLayout id="pglsi1" layout="vertical"
                                 styleClass="AFStretchWidth" halign="center"
                                 inlineStyle="font-size:medium; font-family:Arial, Helvetica, sans-serif;">             
              <af:outputText value="Loading ......" id="ot1"/>
              <af:spacer width="10" height="10" id="s2"/>
              <af:statusIndicator id="si1"/>              
            </af:panelGroupLayout> 
          </f:facet>
          <f:facet name="start">
            <af:panelGroupLayout id="pgl2"/>
          </f:facet>
          <f:facet name="end">
            <af:panelGroupLayout id="pgl3"/>
          </f:facet>
          <f:facet name="top">
            <af:panelGroupLayout id="pgl4"/>
          </f:facet>
        </af:panelStretchLayout>
      </af:form>
    </af:document>
  </f:view>
</jsp:root>

Now, you will see a status indicator during the wait time till the page loads completely



<< A Request >>
  Please contribute in making this world a better place to live in by adopting a pet from your nearest pet shelter (btw cats are my favourite :-) )
<< Thank You >>

Sunday, November 16, 2014

Using xml clob data as data source

Suppose there is table that contains data, such as submitted user application, in xml format and their is a requirement to extract some info from that xml and display it on a web page. For example, the table below contains user application data as xml in AppData column. When a row is selected, the basic information of the user gets extracted from the xml and displayed on the page.


Here are the steps to achieve this:
1. Create JAXB content model from the xsd of xml data content. As a result, Java classes will be generated for each element type of  xsd


2. Create a Java bean class, which will be used later to create a data control. In this class add a property whose data type is the xsd root element type and a method which will populate data for generated Jaxb classes.

import generated.ApplicationType;
import java.io.StringReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.PropertyException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;

public class UserAppDataDC
{
  // XSD top element type
  private ApplicationType userAppData;

  public UserAppDataDC()
  {
    super();
  }

  //Method to populate app data in generated Jaxb classes
  public void getUserAppData(String appData)
  {
    try
    {
      JAXBContext jc = JAXBContext.newInstance(ApplicationType.class);
      StreamSource xml = new StreamSource(new StringReader(appData));
      Unmarshaller unmarshaller = jc.createUnmarshaller();
      JAXBElement<ApplicationType> jaxE1 =
        unmarshaller.unmarshal(xml, ApplicationType.class);
      setUserAppData(jaxE1.getValue());
    }
    catch (PropertyException pe)
    {
      pe.printStackTrace();
    }
    catch (JAXBException jaxbe)
    {
      jaxbe.printStackTrace();
    }
  }

  public void setUserAppData(ApplicationType userAppData)
  {
    this.userAppData = userAppData;
  }
  public ApplicationType getUserAppData()
  {
    return userAppData;
  }
}

3. Right click on the Java bean class and select 'Create Data Control'. Now you can see a data control corresponding to this class in Data Controls panel
4. Start building UI by adding a table component on the page. For getting table data we can simply use a View Object. We do not necessarily need to display the app data colum but the tree attribute binding for it should be available on the page. So, for this example we are using two data controls, a bean data control, which contains data collections corresponding to Jaxb classes and another which contains a VO on the table.



5. Add a method binding for bean data control method.
6. Add a panel form layout with the required attributes from bean data control.
7. Create a custom selection listener for the table in a managed bean. Bind both table and form layout components to managed bean attributes.

public void tableRowSelectionListener(SelectionEvent selectionEvent)
{
// Execute default selection listener behavior
   resolveMethodExpression("#{bindings.UserAppVO.collectionModel.makeCurrent}",
                                         null, new Class[]
            { SelectionEvent.class }, new Object[]
            { selectionEvent });

// Find the method binnding for bean data control method
   OperationBinding op = (OperationBinding)findOperation("getUserAppData");
// Set method parameter with the application data value of the selected row 
 op.getParamsMap().put("appData", getSelectedRowAttribute(getAppDataTable(), "AppData"));
   op.execute();
// Refresh bean data control iterator
    DCIteratorBinding iter = findIterator("UserAppDataDCIterator");
          iter.executeQuery();
          iter.refresh(DCIteratorBinding.RANGESIZE_UNLIMITED);
// Refresh form layout, which displays data extracted from xml
   AdfFacesContext.getCurrentInstance().addPartialTarget(getFormLayout());
    
}

When a row is selected on the table, the selection listener gets the app data from table attribute binding and pass it to the method, which populates data in Jaxb classes. Iterator binding is refreshed subsequently to get the updated data from bean data control.