Thursday Mar 01, 2012

Solving JDeveloper 11gR2 issue with ADF Faces login page in IE8

Using Microsoft IE8, forms based authentication in which the login form is built with ADF Faces doesn't load and instead the browser console report complains about invalid or undefined ADF Faces JavaScript objects. The problem that has been reported for JDeveloper 11g R2 using ADF Faces with Facelets seems to occur only for applications using the ADF Security "ADF Authentication" configuration option in combination with an ADF Faces based login form.

Using the ADF Security "ADF Authentication" option configures the web.xml descriptor to protect the application Java EE context root from unauthenticated access.

 
<security-constraint>
 <web-resource-collection>    
   <web-resource-name>allPages</web-resource-name>    
   <url-pattern>/*</url-pattern>
 </web-resource-collection>
 <auth-constraint>     
   <role-name>valid-users</role-name>
 </auth-constraint>
</security-constraint>

The valid user role name is mapped in the weblogic.xml file and references the WLS users group that all authenticated users are an implicit member of.

<security-role-assignment>   
  <role-name>valid-users</role-name>    
  <principal-name>users</principal-name>
</security-role-assignment>

Protecting the application Java EE root path from unauthenticated access however also means that web resources like pictures or styles sheets, or deferred loaded JavaScript libraries, are blocked until the user has authenticated. For the same reason customers often report missing images on their web login pages.

In the case of an ADF Faces login form, deferred resource loading becomes an issue because subsequent JavaScript requests are all blocked by the security constraint defined in the web.xml file. Surprisingly, this is only a problem in Microsoft IE8 and not with other browsers, which may indicate differences in the handling of login forms and their resource loading. To this time I am not able to say whether IE is doing it right or wrong. Fact however is that the problem only shows on this browser type and that it needs to be handled without opening a security hole, which you would do if you changed the security url-pattern to /faces/* in which case only JSF page requests would require authentication.

Investigating the problem, the following solution has been found by the ADF Faces team: ADF Faces UIs require additional resources that are loaded through the Trinidad resource loader servlet configured in web.xml file.

To allow resources to be loaded when using login forms built with ADF Faces ( in which case the JSF page contains a HTML login form) you need to add another security constraint definition to the web.xml file:

<security-constraint>
  <web-resource-collection>
    <web-resource-name>Allowed ADF Resources</web-resource-name>
    <url-pattern>/adf/*</url-pattern>
    <url-pattern>/afr/*</url-pattern>
    <url-pattern>/bi/*</url-pattern>
  </web-resource-collection>
</security-constraint> 

The above security constraint should do for most of the login pages you would build with ADF Faces. However, if the login screen is more complex and e.g contains DVT graphs or maps, you may have to add more url-patterns for public (anonymous access), like

<url-pattern>/servlet/GraphServlet/*</url-pattern>
<url-pattern>/servlet/GaugeServlet/*</url-pattern>
<url-pattern>/mapproxy/*</url-pattern>
<url-pattern>/adflib/</url-pattern>

In my JDeveloper 11g R2 test-case project, I ended up with three security-constraint definitions added to the web.xml file: "Allowed ADF Resources", "allPages" and "AdfAuthentication".

Always place the "Allowed ADF Resources" security constraint definition first in the web.xml file so it is looked at before all the others are so it takes precedence.

Note that both, the web.xml file and the weblogic.xml file open a visual configuration editor when you double click onto the respective file shown in the JDeveloper Application Navigator (Web Content à WEB-INF folder in the ViewController project.

Wednesday Feb 29, 2012

The infamous Missing IN or OUT parameter error

Often error messages like "attempt to set a parameter name that does not occur in the SQL" and "Missing IN or OUT parameter at index" are caused by developers mixing required and optional bind variables in their SQL queries WHERE clause. If you used bind variables in ADF Business Components SQL queries, make sure the bind variables are set to required. Bind variables that are marked as optional are only good to be used in View Criterias.

In a future version of Oracle JDeveloper, the two bind variable types (the optional ones used in View Criteria and the required ones used in the context of SQL queries) are visually separated in the layout of the View Object editor.

How-to learn ADF Skinning

Recently I observed an increase of questions on OTN and Oracle internal that aim for applying CSS on the generated HTML output of an ADF Faces application. Surely, skinning in ADF is not the same as using CSS in tools like Dreamweaver, but it is the proper way of applying custom images and colors to ADF Faces applications. The biggest risk in styling the generated ADF Faces HTML output with CSS is change in the renderer classes. Oracle constantly works on improving its ADF Faces components, for example using HTML 5 to replace Flash and DHTML on some of the ADF Faces components. If you skinned applications on the generated output, then with each of the changes Oracle applies, your custom styles will break.

ADF sinning applies style sheet definitions to style classes at runtime. In contrast to direct output styling, the style classes are dynamically created and derived from the ADF Faces skin selectors. The component developer ensures that the style classes are always set to the correct location in the generated component output, ensuring that changes last across Oracle JDeveloper versions and component changes. Though I can't save you from learning, I can help you with pointers to sources you want to be aware of:

ADF skinning is documented in the Oracle® Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework

http://docs.oracle.com/cd/E21764_01/web.1111/b31973/af_skin.htm#BAJFEFCJ

An ADF insider recording exists that explains skinning in a 40 minute video. Though this recording doesn't show the new skin editor, you learn a about how skinning works, how you dynamically detect skins at runtime and how you debug skins using FireBug in FireFox.

http://download.oracle.com/otn_hosted_doc/jdeveloper/11gdemos/adf-insider-skinning/adf-insider-skinning.html

As mentioned, a visual skin editor exists that you can use in its stand-alone edition for JDeveloper 11g R1 (11.1.1.4, 11.1.1.5) applications and integrated in JDeveloper 11g R2. An article that explains working with the skin editor and a recommend workflow is published here

http://www.oracle.com/technetwork/issue-archive/2011/11-nov/o61adf-512006.html

To download the stand alone skin editor (JDeveloper 11g R2 has it integrated and no extra download is required), use the link below

http://www.oracle.com/technetwork/developer-tools/adf/downloads/index.html

To learn about the stand alone and the integrate skin editor, refer to the Oracle® Fusion Middleware Skin Editor User's Guide for Oracle Application Development Framework, which you can access online from

http://docs.oracle.com/cd/E16162_01/user.1112/e17456/toc.htm

To try the skin editor on a JDeveloper 11g R2 sample, you can run through the hands-on exercise exposed as part of the Oracle learning library.

http://docs.oracle.com/cd/E18941_01/tutorials/jdtut_11r2_83/jdtut_11r2_83.html

A video recording of how to use the skin editor can be found here

https://blogs.oracle.com/shay/entry/adf_faces_skin_editor_how

 And finally, a list of all skin selectors and ADF Faces components can be read up in the Oracle Fusion Middleware Tag Reference for Oracle ADF Faces Skin Selectors

http://docs.oracle.com/cd/E21764_01/apirefs.1111/e15862/toc.htm

This document is a well written by the ADF Faces component developers and provides information that you don't find in other documentation. If you worked through all of this, Skinning should no longer be a problem for you.

Friday Feb 24, 2012

Learn ADF! Online and for Free!

The Oracle JDeveloper and ADF curriculum team has created a 700 minute online advanced ADF training that is accessible for free from the Oracle Learning library.

https://apex.oracle.com/pls/apex/f?p=44785:24:0::NO::P24_CONTENT_ID,P24_PREV_PAGE:6022,1

Quoting the Oracle Learning library: This self-paced "eCourse" is the first in a series that addresses Oracle ADF 11g topics through video presentations, quizzes and practices. The course was designed to provide you with the most relevant and performance-based learning experience possible in a self-study environment.

You'll find tips, tricks, and best practices from Oracle experts. You decide the way you want to learn as well as the sequence in which you want to study the modules in the course. Topics in Part 1 include:

· ADF Overview

· ADF Bindings

· Project Considerations for Team Development

· ADF Task Flows

Wednesday Jan 18, 2012

How-to determine the ADF tree node type using EL

Creating an ADF tree in ADF produces an entry similar to this in the PageDef file of the view.
<tree IterBinding="AllCountriesIterator" id="AllCountries">
   <nodeDefinition 
        DefName="oracle.summit.model.views.CountryVO" Name="AllCountries0">
     <AttrNames>
       <Item Value="Country"/>
     </AttrNames>
     <Accessors>
       <Item Value="CustomerVO"/>
     </Accessors>
   </nodeDefinition>
   <nodeDefinition 
      DefName="oracle.summit.model.views.CustomerVO" Name="AllCountries1"
      TargetIterator="${bindings.AllCustomersIterator}">
      <AttrNames>
        <Item Value="Id"/>
        <Item Value="Name"/>
     </AttrNames>
   </nodeDefinition>
</tree>

Notice the DefName attribute on each node containing a reference to the actual View Object instance used to render a specific node.

With this information you can now use EL to render the tree nodes differently. For example, the page source below renders the node as a command link if the node presents a customer. For Countries, the node is simply rendered as an output text.
<af:tree value="#{bindings.AllCountries.treeModel}" var="node" ...>
  <f:facet name="nodeStamp">
    <af:group id="g1">
      <af:commandLink id="cl4" text="#{node}"                                                                             
                      rendered="#{node.hierTypeBinding.viewDefName ==  
                                       'oracle.summit.model.views.CustomerVO'}"
      .../>
      
      <af:outputText id="ot4" value="#{node}"                                                                               
               rendered="#{node.hierTypeBinding.viewDefName == 
                                     'oracle.summit.model.views.CountryVO'}"/>
    </af:group>
  </f:facet>
</af:tree>       
The EL expression  #{node.hierTypeBinding.viewDefName} returns the name of the node type, which in ADF is the absolute name of the collection instance rendering the node.

Wednesday Jan 11, 2012

Display selected table row number and total rows

A question on OTN was how to display the current row number and the number of totally available rows in a formatted output string. In the example used below, the format is
row no. [<row index>] of max rows [<total numbers of rows>]

For this example, I used an af:outputText component to display the information on the page. The value of the af:outputText component is calculated from expression language (EL) accessing the ADF binding layer as shown below. Note that for better readability the EL includes line breaks, which in your application you should not add.

 row no. [

#{(bindings.allDepartmentsIterator.rangeStart < 0 ?
1 : bindings.allDepartmentsIterator.rangeStart+1) +

( bindings.allDepartmentsIterator.currentRowIndexInRange == -1 ?

0 : bindings.allDepartmentsIterator.currentRowIndexInRange)}
]

of max rows[

#{bindings.allDepartmentsIterator.estimatedRowCount}]

Note how the expression uses the iterator binding in the ADF binding layer to determine the maximum number of table rows. It then uses the same iterator to determine the current row. Because iterators are zero based, the EL uses additional logic to compensate this.

The af:outputText component needs to have its PartialTriggers property pointing the the af:table component ID to ensure the displayed information is refreshed when the table row currency changes.

 <af:outputText value="row no. [#{(bindings.allDepartmentsIterator.rangeStart &lt; 0 ? 1  :  bindings.allDepartmentsIterator.rangeStart+1) +( bindings.allDepartmentsIterator.currentRowIndexInRange ==  -1 ? 0 : bindings.allDepartmentsIterator.currentRowIndexInRange)}] of max rows [#{bindings.allDepartmentsIterator.estimatedRowCount}]"
                id="ot1" partialTriggers="pc1:t1"/>


Tuesday Dec 27, 2011

Using JSTL in ADF Faces

The JavaServer Pages Standard Tag Library (JSTL) provides expressions for common web application functionalities. Though JavaServer Faces Expression Language (EL) is different from JSTL expressions, the two can be used in combination for functional for which it makes sense. For example, the table below lists JSTL expressions that operate on String values.

Function

Description

fn:contains()

Tests if an input string contains the specified substring.

fn:containsIgnoreCase()

Tests if an input string contains the specified substring in a case insensitive way.

fn:endsWith()

Tests if an input string ends with the specified suffix.

fn:escapeXml()

Escapes characters that could be interpreted as XML markup.

fn:indexOf()

Returns the index withing a string of the first occurrence of a specified substring.

fn:length()

Returns the number of items in a collection, or the number of characters in a string.

fn:replace()

Returns a string resulting from replacing in an input string all occurrences with a given string.

fn:startsWith()

Tests if an input string starts with the specified prefix.

fn:substring()

Returns a subset of a string.

fn:substringAfter()

Returns a subset of a string following a specific substring.

fn:substringBefore()

Returns a subset of a string before a specific substring.

fn:toLowerCase()

Converts all of the characters of a string to lower case.

fn:toUpperCase()

Converts all of the characters of a string to upper case.

fn:trim()

Removes white spaces from both ends of a string.

Src: http://www.tutorialspoint.com/jsp/jsp_standard_tag_library.htm

To use JSTL in Oracle ADF Faces component EL references, you need to add the JSTL namespace of the tags you want to reference. For the JSTL functions shown in the table above, you need to manually add the name space highlighted in red to the JSPX document or page fragment.

<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"        
 xmlns:fn="http://java.sun.com/jsp/jstl/functions">

The value expression below, referenced in an af:outputText component, displays the substring (first, second and third character) for a value read from the ADF binding layer.

<af:outputText value="#{fn:substring(bindings.employeeName.inputValue,1,3)}" id="ot7"/>

Friday Nov 25, 2011

How to detect browser type and version from ADF Faces

Sometimes ADF applications need to know about the user browser type and version. For this, assuming you need this information in Java, you can use the Trinidad RequestContext object. You could also use the AdfFacesContext object for the same, but since the ADF Faces Agent class is marked as deprecated, using the equivalent Trinidad classes is the better choice.

The source code below prints the user browser information to the Oracle JDeveloper message window

import org.apache.myfaces.trinidad.context.Agent;
import org.apache.myfaces.trinidad.context.RequestContext;



RequestContext requestCtx = RequestContext.getCurrentInstance();
Agent agent = requestCtx.getAgent();
String version = agent.getAgentVersion();
String browser = agent.getAgentName();
String platform = agent.getPlatformName();
String platformVersion = agent.getPlatformVersion();

System.out.println("==================");
System.out.println("Your browser information: ");
System.out.println("Browser: "+browser);
System.out.println("Browser Version : "+version);
System.out.println("Browser Platform: "+platform);
System.out.println("Browser Platform Version:
"+platformVersion);
System.out.println("==================");


Thursday Nov 24, 2011

Accessing the JSESSIONID from JSF

The following code attempts to access and print the user session ID from ADF Faces, using the session cookie that is automatically set by the server and the Http Session object itself.

FacesContext fctx = FacesContext.getCurrentInstance();
ExternalContext ectx = fctx.getExternalContext();
HttpSession session = (HttpSession) ectx.getSession(false);
String sessionId = session.getId(); 
System.out.println("Session Id = "+ sessionId); 
Cookie[] cookies = 
 ((HttpServletRequest)ectx.getRequest()).getCookies(); 
//reset session string
sessionId = null; 
if
(cookies != null) {
 for (Cookie brezel : cookies) {
     if (brezel.getName().equalsIgnoreCase("JSESSIONID")) {
       sessionId = brezel.getValue();
       break;
     }
  } 
} 
System.out.println("JSESSIONID cookie = "+sessionId);

Though apparently both approaches to the same thing, they are different in the value they return and the condition under which they work. The getId method, for example returns a session value as shown below

grLFTNzJhhnQTqVwxHMGl0WDZPGhZFl2m0JS5SyYVmZqvrfghFxy!-1834097692!1322120041091

Reading the cookie, returns a value like this

grLFTNzJhhnQTqVwxHMGl0WDZPGhZFl2m0JS5SyYVmZqvrfghFxy!-1834097692

Though both seem to be identical, the difference is within "!1322120041091" added to the id when reading it directly from the Http Session object. Dependent on the use case the session Id is looked up for, the difference may not be important.

Another difference however, is of importance. The cookie reading only works if the session Id is added as a cookie to the request, which is configurable for applications in the weblogic-application.xml file. If cookies are disabled, then the server adds the session ID to the request URL (actually it appends it to the end of the URI, so right after the view Id reference). In this case however no cookie is set so that the lookup returns empty. In both cases however, the getId variant works.

Tuesday Nov 22, 2011

Creating ADF Faces Comamnd Button at Runtime

In ADF Faces, the command button is an instance of RichCommandButton and can be created at runtime. While creating the button is not difficult at all, adding behavior to it requires knowing about how to dynamically create and add an action listener reference. The example code below shows two methods: The first method, handleButtonPress is a public method exposed on a managed bean.

public void handleButtonPress(ActionEvent event){ 
 System.out.println("Event handled"); 
 //optional: partially refresh changed components if command 
 //issued as a partial submit
}

The second method is called in response to a user interaction or on page load and dynamically creates and adds a command button. When the button is pressed, the managed bean method – the action handler – defined above is called. The action handler is referenced using EL in the created MethodExpression instance. If the managed bean is in viewScope, backingBeanScope or pageFlowsScope, then you need to add these scopes as a prefix to the EL (as you would when configuring the managed bean reference at design time)

//Create command button and add it as a child to the parent component that is passed as an 
//argument to this method
private void reateCommandButton(UIComponent parent){
  RichCommandButton edit = new RichCommandButton();
  //make the request partial
  edit.setPartialSubmit(true);
  edit.setText("Edit");                         
  
  //compose the method expression to invoke the event handler
  FacesContext fctx = FacesContext.getCurrentInstance();
  Application application = fctx.getApplication();
  ExpressionFactory elFactory = application.getExpressionFactory();
  ELContext elContext = facesCtx.getELContext();
  MethodExpression methodExpressio = null;
  //Make sure the EL expression references a valid managed bean method. Ensure
  //the bean scope is properly addressed 

  methodExpression =  elFactory.createMethodExpression( 
                            elContext,"#{myRequestScopeBean.handleButtonPress}", 
                            Object.class,new Class[] {ActionEvent.class});
  //Create the command buttonaction listener reference

  MethodExpressionActionListener al = null;        
  al= new MethodExpressionActionListener(methodExpression); 
  edit.addActionListener(al); 

   //add new command button to parent component and PPR the component for 
   //the button to show
   parent.getChildren().add(edit);
   AdfFacesContext adfFacesContext = AdfFacesContext.getCurrentInstance(); 
   adfFacesContext.addPartialTarget(parent); 
}

How-to read data from selected tree node

By default, the SelectionListener property of an ADF bound tree points to the makeCurrent method of the FacesCtrlHierBinding class in ADF to synchronize the current row in the ADF binding layer with the selected tree node. To customize the selection behavior, or just to read the selected node value in Java, you override the default configuration with an EL string pointing to a managed bean method property. In the following I show how you change the selection listener while preserving the default ADF selection behavior.

To change the SelectionListener, select the tree component in the Structure Window and open the Oracle JDeveloper Property Inspector. From the context menu, select the Edit option to create a new listener method in a new or an existing managed bean.

For this example, I created a new managed bean. On tree node select, the managed bean code prints the selected tree node value(s)


import java.util.List;

import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.faces.application.Application;
import javax.faces.context.FacesContext;

import java.util.Iterator;  
import oracle.adf.view.rich.component.rich.data.RichTree;
import oracle.jbo.Row;
import oracle.jbo.uicli.binding.JUCtrlHierBinding;
import oracle.jbo.uicli.binding.JUCtrlHierNodeBinding;
import org.apache.myfaces.trinidad.event.SelectionEvent;

import org.apache.myfaces.trinidad.model.CollectionModel;
import org.apache.myfaces.trinidad.model.RowKeySet;
import org.apache.myfaces.trinidad.model.TreeModel;  
public class TreeSampleBean {
 public TreeSampleBean() {}
 public void onTreeSelect(SelectionEvent selectionEvent) {
  //original selection listener set by ADF
  //#{bindings.allDepartments.treeModel.makeCurrent}
  String adfSelectionListener = "#{bindings.allDepartments.treeModel.makeCurrent}";
  //make sure the default selection listener functionality is 
  //preserved. you don't need to do this for multi select trees 
  //as the ADF binding only supports single current row selection  
 
  /* START PRESERVER DEFAULT ADF SELECT BEHAVIOR */
  FacesContext fctx = FacesContext.getCurrentInstance();
  Application application = fctx.getApplication();
  ELContext elCtx = fctx.getELContext();
  ExpressionFactory exprFactory = application.getExpressionFactory();
  
  MethodExpression me = null;
  me = exprFactory.createMethodExpression(elCtx, adfSelectionListener, 
                                          Object.class, newClass[]{SelectionEvent.class}); 
  me.invoke(elCtx, new Object[] { selectionEvent });  

  /* END PRESERVER DEFAULT ADF SELECT BEHAVIOR */
  RichTree tree = (RichTree)selectionEvent.getSource();
  TreeModel model = (TreeModel)tree.getValue();   
 
  //get selected nodes
  RowKeySet rowKeySet = selectionEvent.getAddedSet(); 
  Iterator rksIterator = rowKeySet.iterator(); 
  //for single select configurations,this only is called once 
  while (rksIterator.hasNext()) {
    List key = (List)rksIterator.next();
    JUCtrlHierBinding treeBinding = null;
    CollectionModel collectionModel = (CollectionModel)tree.getValue();
    treeBinding = (JUCtrlHierBinding)collectionModel.getWrappedData(); 
    JUCtrlHierNodeBinding nodeBinding = null;
    nodeBinding = treeBinding.findNodeByKeyPath(key);
    Row rw = nodeBinding.getRow();
    //print first row attribute. Note that in a tree you have to 
    //determine the node type if you want to select node attributes 
    //by name and not index 
    String rowType = rw.getStructureDef().getDefName();
  
    if(rowType.equalsIgnoreCase("DepartmentsView")){
      System.out.println("This row is a department: " +  
                         rw.getAttribute("DepartmentId"));
    }
    else if(rowType.equalsIgnoreCase("EmployeesView")){
     System.out.println("This row is an employee: " + 
                         rw.getAttribute("EmployeeId"));
    }     
    else{
      System.out.println("Huh????");  
    }
    // ... do more useful stuff here   
  }   

}

--------------------

Download JDeveloper 11.1.2.1 Sample Workspace


Thursday Nov 17, 2011

Reading train stop display names from a resource bundle

In Oracle JDeveloper 11g R1, you set the display name of a train stop of an ADF bounded task flow train model by using the Oracle JDeveloper Structure Window.

To do so

  • Double-click onto the bounded task flow configuration file (XML) located in the Application Navigator so the task flow diagram open
  • In the task flow diagram, select the view activity node for which you want to define the display name.
  • In the Structure Window., expand the view activity node and then the train-stop node therein
  • Add the display name element by using the right-click context menu on the train-stop node, selecting Insert inside train-stop > Display Name
  • Edit the Display Name value with the Property Inspector

Following the steps outlined above, you can define static display names – like "PF1" for page fragment 1 shown in the image below - for train stops to show at runtime.

In the following, I explain how you can change the static display string to a dynamic string that reads the display label from a resource bundle so train stop labels can be internationalized.

There are different strategies available for managing message bundles within an Oracle JDeveloper project. In this blog entry, I decided to build and configure the default properties file as indicated by the projects properties. To learn about the suggested file name and location, open the JDeveloper project properties (use a right mouse click on the project node in the Application Navigator and choose Project Properties.

Select the Resource Bundle node to see the suggested name and location for the default message bundle. Note that this is the resource bundle that Oracle JDeveloper would automatically create when you assign a text resource to an ADF Faces component in a page.

For the train stop display name, we need to create the message bundle manually as there is no context menu help available in Oracle JDeveloper. For this, use a right mouse click on the JDeveloper project and choose New | General | File from the menu and in the opened dialog.

Specify the message bundle file name as the name looked up before in the project properties Resource Bundle option. Also, ensure that the file is saved in a directory structure that matches the package structure shown in the Resource Bundle dialog. For example, you would save the properties file in the View Project's src > adf > sample directory if the package structure was "adf.sample" (adf.sample.ViewControllerBundle).

Edit the properties file and define key – values pairs for the train stop component. In the sample, such key value pairs are

TrainStop1=Train Stop 1
TrainStop2=Train Stop 2
TrainStop3=Train Stop 3

Next, double click the faces-config.xml file and switch the opened editor to the Overview tab. Select the Application category and press the green plus icon next to the Resource Bundle section.

Define the resource bundle Base Name as the package and properties file name, for example

adf.sample.ViewControllerBundle

Finally, define a variable name for the message bundle so the bundle can be accessed from Expression Language. For this blog example, the name is chosen as "messageBundle".

<resource-bundle>
  <base-name>adf.sample.ViewControllerBundle</base-name>
  <var>messageBundle</var>
</resource-bundle> 

Next, select the display-name element in the train stop node (similar to when creating the display name) and use the Property Inspector to change the static display string to an EL expression referencing the message bundle. For example:

#{messageBundle.TrainStop1}

At runtime, the train stops now show display names read from a message bundle (the properties file).

Tuesday Nov 01, 2011

Using ADF logger with Groovy in ADF BC

Groovy is a scripting language that can be used in the context of ADF BC. It simplifies Java object access and method execution. Basically everything you could access from Java you can access from Groovy. If logging is needed in your Groovy scripting, then this can be achieved using the ADF Logger as shown below. Just add script similar to this into the Groovy code are (e..g when working with custom entity validators)

//log information to console. Create a logger instance for
//the entity class – "Employees in this sample

oracle.adf.share.logging.ADFLogger LOGGER =
oracle.adf.share.logging.ADFLogger.
createADFLogger(source.getClass())

LOGGER.info("Groovy Log Statement: oldValue and newValue in Validdator
"+oldValue+" ---> "+newValue)

LOGGER.info("Groovy Log Statement: All salaries in Department
"+Departments1.Employees1.sum('Salary'))

LOGGER.info("Groovy Log Statement: current budget "+(100000 -
(Departments1.Employees1.sum('Salary')+ newValue) + oldValue ))

Like In Java, you define a variable to hold the logger reference to then use it to print info messages

Friday Oct 14, 2011

How to programmatically set focus on an input component

The af:document component has a property InitialFocusId that allows you to define the Id of an input component that should take focus when a page initially loads. But how do you set the component focus for pages that are already rendered? A use case for this is a partial submit that executes logic on the server, after which the cursor focus in the UI needs to be set to a specific input component of a page or page fragment. The solution to this use case is JavaScript that is generated on the server and executed on the client.

The simplified sample I wrote contains of three input text fields and three command buttons. Initially, using the af:document InitialFocusId property, the cursor focus is set to the first input text field.

The command button send a partial submit to a managed bean on the server. The managed bean reads the component Id of the input text field to put the focus to from a client attribute that is defined on each command button. Using the MyFaces Trinidad ExtendedRenderKitService class, the managed bean sends a JavaScript call to the client to change the current component focus.

Important: By default, ADF Faces does not render all its user interface components as JavaScript objects. It only renders those components as JavaScript objects that have behavior, like a table that can have its columns moved. Input text components, for example, are rendered in HTML only, which means that the ADF client side JavaScript framework will not find a handle to the component unless you tell ADF Faces to create one. For this, you set the ClientComponent property of the input text fields to true. This also is required for the af:document InitialFocusId property to work.

Below is the managed bean code that handles the command button action and that composes and executes the JavaScript to set the client side UI focus.

import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import oracle.adf.view.rich.component.rich.input.RichInputText;
import oracle.adf.view.rich.component.rich.nav.RichCommandButton;
import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
import org.apache.myfaces.trinidad.util.Service;
public
class FocusBean {
  public FocusBean() {
  }

 public String onSetFocus(ActionEvent event) {
   RichCommandButton rcb = (RichCommandButton)event.getSource();
   String focusOn = (String)rcb.getAttributes().get("focusField");
   FacesContext fctx = FacesContext.getCurrentInstance();
   UIViewRoot viewRoot = fctx.getViewRoot();
  //search can be improved to include naming containers
  RichInputText rit = RichInputText)viewRoot.findComponent(focusOn);
 if (rit != null) {
   String clientId = rit.getClientId(fctx); 
   //compose JavaScript to be executed on the client 
   StringBuilder script = new StringBuilder();
   //use client id to ensure component is found if located in
   //naming container  
   script.append("var textInput = ");
   script.append("AdfPage.PAGE.findComponentByAbsoluteId");
   script.append ("('"+clientId+"');");
 
   script.append("if(textInput != null){"); 
   script.append("textInput.focus();");
   script.append("}");
   //invoke JavaScript
   writeJavaScriptToClient(script.toString());
  }  
 }
  //generic, reusable helper method to call JavaScript on a client
  private void writeJavaScriptToClient(String script) {
    FacesContext fctx = FacesContext.getCurrentInstance();
    ExtendedRenderKitService erks = null;
    erks = Service.getRenderKitService(
                 fctx, ExtendedRenderKitService.class);
    erks.addScript(fctx, script);
  }
}

 As mentioned, the command buttons in the sample have a client attribute attached that I use to determine which input component should receive focus. The managed bean calls the client attribute here:

RichCommandButton rcb = (RichCommandButton)event.getSource();
String focusOn = (String)rcb.getAttributes().get("focusField");

 In the page definition, the client attribute is defined as

<af:commandButton text="Focus Field 2" id="commandButton1"
                   partialSubmit="true"
                   actionListener="#{FocusBean.onSetFocus}">
  <af:clientAttribute name="focusField" value="it2"/>
</af:commandButton>
<af:commandButton text="Focus Field 3" id="cb1"
                  partialSubmit="true"
 actionListener="#{FocusBean.onSetFocus}">
  <af:clientAttribute name="focusField" value="it3"/>
</af:commandButton>

In your custom implementation of this use case, you for sure will have your own way of determining the next focus target. The server side code however doesn't change much.

You can DOWNLOAD the sample workspace from here: http://blogs.oracle.com/jdevotnharvest/resource/SetFocusToField.zip


Friday Jul 08, 2011

How-to access UI component that queued a custom client event

In ADF Faces, to invoke a server side method in a managed bean, you use the af:serverListener tag. The af:serverListener tag is added as a child to the component that owns the event and called from JavaScript in a call to AdfCustomEvent.queue( … )

In this example, the af:serverListener is added to a table to notify a manage bean method about a double-click action.

<af:table ...>
 <af:column> ... </af:column>
 ...
 <af:clientListener method="handleTableDoubleClick"
                   type="dblClick"/>
<af:serverListener type="TableDoubleClickEvent"                          
                   method="#{myBean.handleTableDoubleClick}"/>
</af:table> 

The JavaScript function that is called by the af:clientListener is shown next.

function handleTableDoubleClick(evt){   
  var table = evt.getSource();
  AdfCustomEvent.queue(table, "TableDoubleClickEvent",{}, true);         
  evt.cancel();
}

The first argument in the call to AdfCustomEvent.queue represents the event owner, the table component. This information is passed to the managed bean method, which has the following signature.

public void handleTableDoubleClick(ClientEvent ce){
  RichTable richTable = (RichTable)ce.getComponent(); 
  //... work with rich table component
}

As you can see, there is no need to look up the event owning component by searching the JSF UIViewRoot with or without help of JSFUtils.

About

The Oracle JDeveloper forum ranks in the Top 5 of the most active forums on the Oracle Technology Network (OTN).



The OTN Harvest blog is a summary of selected topics posted on the OTN Oracle JDeveloper forum.



It is an effort to turn knowledge exchange into an interesting read for developers who enjoy little nuggets of wisdom





Frank Nimphius

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today