Wednesday, January 18, 2012

ADF common errors: How to get selected row from table ?

In many blogs I found above question and solution like this:

FacesCtrlHierBinding rowBinding = (FacesCtrlHierBinding) tab.getSelectedRow();
Row rw = rowBinding.getRow();

or 

RichTable _table = (RichTable ) selectionEvent.getSource();
CollectionModel model = (CollectionModel ) _table.getValue();
FacesCtrlHierBinding _binding = (FacesCtrlHierBinding) model.getWrappedData();
FacesCtrlHierBinding.FacesModel treeModel = (FacesCtrlHierBinding.FacesModel) _binding.getTreeModel();
treeModel.makeCurrent(selectionEvent);


On first sight FacesCtrlHierBinding exposes the convenient methods you need. But the solution is invalid. You shouldn't use FacesCtrlHierBinding and FacesCtrlHierNodeBinding directly cause they are internal ADF Faces component model for tree, table and treeTable.

You can use EL in Java: #{bindings.myEntityView.treeModel.makeCurrent}:
  • Easy to use
  • Does it right for all Data Control types
  • Requires knowledge about the PageDef definition
or



Use JUCtrlHierBinding or JUCtrlHierNodeBinding
  • No knowledge about binding layer is required
  • Needs more code to write
By example:


RichTable _table = (RichTable ) selectionEvent.getSource();
CollectionModel model = (CollectionModel ) _table.getValue();
JUCtrlHierBinding _binding = (JUCtrlHierBinding) model.getWrappedData();
DCIteratorBinding iteratorBinding = _binding.getDCIteratorBinding();
Object _selectedRowData = _table´.getSelectedRowData();
JUCtrlHierNodeBinding node = (JUCtrlHierNodeBinding) _selectedRowData ;
Key rwKey = node.getRowKey();
iteratorBinding.setCurrentRowWithKey(rwKey.toStringFormat(true));

ADF: Errors when prefix managed bean EL references with the scope name

As you can see in Oracle products documentation, managed beans can be referenced with scope prefix if they are defined in backingBeanScope, viewScope or pageFlowScope as these are custom ADFc scopes. Also requestScope and sessionScope are available.

<af:outputtext value="#{requestScope.MyBean.MyCityName}"/>


But accessing managed beans with expressions with scope prefix can potentially cause NPE errors.

For servlet scopes like request, session and application, using a prefix will cause NPE for when you access a managed bean that hasn't been instantiated before. So for all regular servlet scopes, don't use a prefix when accessing managed beans.

Scope prefixes doesn’t always work for beans in default Servlet scopes: requestScope, sessionScope, applicationScope. The prefix mechanism for servlet scopes bypasses JavaServer Faces managed bean facility:
  • Only looks for in-memory objects
  • Does not instantiate managed beans (it will cause NPE for when you access a managed bean that hasn't been instantiated before) 
  • Using this is only good idea if looking up memory attributes you know exist or you want to create
Scope prefixes works for ADF specific scopes: viewScope, pageFlowScope, backingBeanScope.
  • ADFc controller takes care of managed bean instantiation if configuration is available

Friday, January 13, 2012

Old but useful artice regarding servlet filters

I found today a useful article about servlet filters. The informations aren't new, but are given in an orderly manner with references to servlet api and contain some examples.
If you are interested in informations about filter models or in useful examples of filter implementations, go to: http://www.servlets.com/soapbox/filters.html

Friday, December 30, 2011

Adding Javascripts or inline CSS to ADF page

The best way to add javascript or css to ADF page is use of af:resource. This component adds CSS or JavaScript resource to rendered HTML header. Tag af:resource is processed on the initial creation of the document.

You can point external js or css file, as shown bellow:

<af:document>
   <af:resource type="javascript" source="/js/MyJsCode.js"/>
...
</af:document>


or insert javascript / css code inside tag body:

<af:document>
   <af:resource type="javascript">

      function myJavascriptFunction(){
          alert('This is my function');
      }
   </af:resource>
...
</af:document>


The parent of a af:resource component should be af:document. There is not recommended use of af:resource inside other adf component.

Another way of adding scripts/css to ADF page is "standard" JSF way:
<af:document>
...

   <f:facet>
      <script type="text/javascript">
          function myJavascriptFunction(){
            alert('This is my function');

          }
      </script>
   </f:facet>
...
</af:document>


If you need put CSS into <f:facet> you can encounter problems when compiling. To avoid simillar problems you can wrap tags <style></style> section <![CDATA[ ]]>.

ADF: Custom Client Attributes

As Oracle say:
"The clientAttribute tag specifies the name/value for an attribute which will both be made available both on the server-side (Faces) component as well on on the client-side equivalent. This tag will be ignored for any server-rendered components, as it is only supported for the rich client. ClientAttributes are not synchronized to the server since unknown attributes from the client are not synchronized to the server."

Client attributes simply allows developers to add custom properties to an ADF Faces component instance. Next JavaScript can read custom attribute by calling the getProperty('attr_name') function on a component handle.

Use case:
  • passing to Javascript additional infromation, out of scope for the component.
  • passing to the client Context informations
  • alternative to Javascript callback

Thursday, December 29, 2011

How-to find ADF Faces Components on a Page using javascript

Search from AdfPage.PAGE
  • Search by the component ID - use findComponentByAbsoluteId function
  • Search in component that stamps its children - use findComponentByAbsoluteLocator function
 Relative Search
  •  Use findComponent function. This function searches the component clientId which can be renderer implementation specific.
 Ensure a component exists on the client before accessing it from JavaScript. To ensure client component exists (is rendered)  set clientComponent property to true.

AdfPage.PAGE.findComponentByAbsoluteLocator example:

<af:document title="Page1" id="d1">
  <af:form id="f1">
    <af:panelStretchLayout id="psl1">
      <f:facet name="center">
        <af:panelGroupLayout id="pgl1">
          <af:panelGroupLayout id="main" styleClass="AFStretchWidth" layout="vertical">
          ...
          </af:panelGroupLayout>
        </af:panelGroupLayout>
      </f:facet>
    </af:panelStretchLayout>


    <af:resource type="javascript">
      function f1(){
        var main = AdfPage.PAGE.findComponentByAbsoluteId('main');
         alert(main);
        if(main != null) {
          ActionEvent.queue(main, true);
        }
      }
    </af:resource>
    ...

Wednesday, December 28, 2011

ADF custom phase listeners

As we know developers can create and configure custom life cycle listeners to receive ADF lifecycle notifications at the beginning and the end of each phase to execute custom logic.

In Oracle ADF framework developer can use standard JSF listener or special ADF listener which supports additional ADF-specific page cycle extensions. Listeners can be used to customize the ADF Lifcycle.

Custom listener can beconfigured for the following scopes:
  • Global, when the page lifecycle listener is configured to execute for all lifecycle execution throughout the application
  • Page scope - the listener is configured in the page definition file and supports concrete page
  • Custom scope - a lifecycle listener is added programmatically from Java and remains active until it is removed or the user session is dismissed
 How to create listener?
  • Create an objects that should receive lifecycle notifications. The object must implement the PagePhaseListener interface
  • The method argument is an instance of PagePhaseEvent.
  • PhaseId returns phase identifier (int value)
  • ADF controller is requred
  • To create and configure global lifecycle listener use the adf-settings.xml configuration file. The adf-settings.xml file does not exist by default and needs to be created in the “.adf\META-INF” folder of the application. The adf-settings.xml file allows developers to define the order in which page phase listeners are invoked.
Example:
public class MyPageListener implements PagePhaseListener {

    public MyPageListener() {

        super();

    }

    public void afterPhase(PagePhaseEvent pagePhaseEvent) {

        String phaseId = pagePhaseEvent.getPhaseId();

        System.out.println("We are after "+ Lifecycle.getPhaseName(phaseId));

    }

    public void beforePhase(PagePhaseEvent pagePhaseEvent){

        String phaseId = pagePhaseEvent.getPhaseId();

        System.out.println("We are before "+ Lifecycle.getPhaseName(phaseId));

    }

}

<?xml version="1.0" encoding="US-ASCII" ?>
<adf-settings xmlns="http://xmlns.oracle.com/adf/settings">
  <adfc-controller-config xmlns="http://xmlns.oracle.com/adf/controller/config">
    <lifecycle>
      <phase-listener>
        <listener-id>MyPageListener1</listener-id>
        <class>mc.adf.listeners.MyPageListener</class>
        <before-id-set>
          <listener-id> MyPageListener2</listener-id>
        </before-id-set>
        <after-id-set>
          <listener-id>MyPageListener3</listener-id>
        </after-id-set>
     </phase-listener>
    </lifecycle>
  </adfc-controller-config>
</adf-settings>