Friday Apr 20, 2012

Which option to choose for accessing Web Services in ADF

Oracle ADF provides three options for integrating Web Service:

· Web Service Data Control

· JAX-WS proxy client and POJO Data Control

· JAX-WS proxy client and programmatic View Objects

Note: In the above, I exclude REST services in my recommendation because this is what ADF will address much better using the URL data control in JDeveloper 11g R2 (available) and with improved functionality in the upcoming Oracle JDeveloper 12c release.

For deciding which option to use for integrating Web Service, here is what I consider "a good rule of thumb"

1. Use Web Service Data Control only for simple service like weather reports or stock quotes

2. Use JAX-WS proxy client for all more complex services and access them from

a. Programmatic view object and entity if your business service is ADF Business Components as this allows for better integration with database queried  views

i. Use View Objects only for read only access

ii. Use View Objects and Entities for CRUD Web Service integration

b. POJO Data Control

i. If your business service is not ADF BC.

ii. If the WS doesn't require integration in ADF business component

iii. If WS access should be from a bounded task flow in an ADF library for maximum reuse

As a general hint of best practice: Never use the JAX-WS generated proxy client directly. Always access it from a wrapper bean to avoid code losses or problem in cases where the proxy client needs to be re-generated.

Note: ADF Code Corner published an article explaining how to cache Web Services results when using JAX-WS proxy clients to avoid unnecessary round trips. See: http://www.oracle.com/technetwork/developer-tools/adf/learnmore/92-cache-ws-queries-523136.pdf


        
    

Wednesday Apr 18, 2012

Task Flow navigation using QueueActionEventInRegion on ADF Region

A common requirement in Oracle ADF is to perform navigation within an ADF region triggered by the parent page. While contextual event is one option to perform this task, the queueActionEventInRegion method exposed on the RichRegion instance is another. The queueActionEventInRegion performs navigation following control flow cases defined for the current view exposed in the region. Control flow cases can be flows that are defined from the view activity to a next activity or wild card control flow cases.

The easiest way for developers to access the RichRegion instance of an af:region tag is to use its Binding property and point it to a managed bean. Once you have a handle to the RichRegion, you can perform navigation from any event raised on the parent view (e.g. menu items action, command button action, value change events etc.)

//process navigation
public String navPickerAction() {
  //get selected navigation option
  String navigationCase = this.currentNavOption;
  RichRegion region = this.findRegionById("adfRegion1");
        
  region.queueActionEventInRegion(createMethodExpressionFromString(navigationCase), 
                                  null, null,false, 0, 0, PhaseId.INVOKE_APPLICATION);     
  return null;
}
    
//Create Method expression    
private MethodExpression createMethodExpressionFromString(String s){
  FacesContext fctx = FacesContext.getCurrentInstance();
  ELContext elctx = fctx.getELContext();
  ExpressionFactory exprFactory = fctx.getApplication().getExpressionFactory();
  MethodExpression methodExpr = exprFactory.createMethodExpression( 
                 elctx,               
                 s,
                 null, 
                 new Class[]{});  
  return methodExpr;
}

Another useful method on the RichRegion instance is the ability to peek into the region for control flow cases defined for the current view. The following code reads the control flow cases that are defined for a view in a region to build a list of SelectItem for use in an af:selectOneChoice

//read the navigation case list from the region capabilities
public ArrayList<SelectItem> getNavlist() {
   RichRegion region = this.findRegionById("adfRegion1");
   Set<String> capabilities = region.getRegionModel().getCapabilities();
   navlist = new ArrayList<SelectItem>();
     
   for(String navcase : capabilities){            
     SelectItem item = new SelectItem();
     item.setLabel(navcase);
     item.setValue(navcase);
     navlist.add(item);            
   }
       
   return navlist;
}

The JDeveloper 11.1.1.6 sample workspace you can download at the end blog article contains implementations for all RichRegion methods: queueActionEventInRegion, getCapabilities and RegionNavigationListener

sample

The select one choice in component in the sample always shows the control flow cases that are defined for the current view in the ADF Region (just for fun, you may want to add some wild card navigation flows in the task flow and then re-run the application to see that the control flow cases are dynamically looked up). Using the Region Navigation Listener, navigating the region using the "Go to Employees" button on the view will update the select one choice component in the parent view.

Get the sample application from here and make sure you configure the database connect to point to the HR schema of your local Oracle database.

Download Sample


Wednesday Mar 28, 2012

Gotcha when using JavaScript in ADF Regions

You use the ADF Faces af:resource tag to add or reference JavaScript on a page. However, adding the af:resource tag to a page fragment my not produce the desired result if the script is added as shown below

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
 <af:resource type="javascript">
  function yourMethod(evt){ ... }
</af:resource>

Adding scripts to a page fragment like this will see the script added for the first page fragment loaded by an ADF region but not for any subsequent fragment navigated to within the context of task flow navigation. The cause of this problem is caching as the af:resource tag is a JSP element and not a lazy loaded JSF component, which makes it a candidate for caching.

To solve the problem, move the af:resource tag into a container component like af:panelFormLayout so the script is added when the component is instantiated and added to the page. 

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
<af:panelFormLayout>
 <af:resource type="javascript">
    function yourMethod(evt){ ... }
 </af:resource>
</af:panelFormLayout> 

Magically this then works and prevents browser caching of the script when using page fragments.

Monday Mar 19, 2012

URL Task Flow vs. WSRP Portlets

A URL task flow is bounded task flow that is deployed as a stand-alone Java EE application on a remote server with its URL Invoke property set to url-invoke-allowed. The URL task flow is accessed either from a direct browser GET request or, when called from another ADF application, through the task flow call activity.

For more information about how to invoke URL task flows from a task flow call activity see chapter 15.6.4 How to Call a Bounded Task Flow Using a URL of the Oracle Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework at

http://docs.oracle.com/cd/E23943_01/web.1111/b31974/taskflows_activities.htm#CHDJDJEF

Compared to WRSP portlets, URL task flows in Oracle JDeveloper 11g R1 and R2 have a functional limitation in that they cannot be embedded as a region on a page but require the calling ADF application to navigate off to another application and page. The difference between a URL task flow call using the task flow call activity and a simple redirect to a remote Java EE application is that the URL task flow has a state token attached that allows to restore the state of the calling application upon task flow return.

A use case for a URL task flow call activity is a "yellow page lookup" scenario in which different ADF applications use an URL task flow to lookup people, products or similar to return a selected value to the calling application.

Note that URL task flow calls need to be performed from a bounded or unbounded top level task flow of the calling application. If called from a region (using the parent call activity) in a page, the region state is not recovered upon task flow return.

ADF developers recently have identified URL task flows as an architecture pattern to partition their ADF applications into independently deployed Java EE applications. While this sounds like a desirable use of the URL task flow feature, it is not possible to achieve for as long as URL task flows don't render as an ADF region.

Thursday Mar 08, 2012

Using af:serverListener as a JS client-server proxy

Despite of ADF Faces having a client side JavaScript architecture, JavaScript rule #1 in ADF Faces is to use JavaScript as a fallback option only for development use cases in which there is no native solution to a problem. A built-in feature of the ADF Faces JavaScript client architecture is security that disallows certain component properties like disabled and readOnly to be changed from JavaScript.

To quote the JavaScript doc for the AdfRichInputText object:

http://docs.oracle.com/cd/E12839_01/apirefs.1111/e12046/oracle/adf/view/js/component/rich/input/AdfRichInputText.html#getReadOnly__

public Boolean getReadOnly()

Get function for attribute for 'readOnly'. This attribute is secured. You may get it, but you may not set it. Any changes to this attribute will not be transmitted to the server.

Note: The disabled property can be enabled for JavaScript modification by setting the component unsecure property as explained in the component documentation, which however I don't recommend you to do. If you need to open protected features for modification, do so in a way that you control, for example in that you can check a user permission to do so.

There might be use cases in which you need to change a protected property from JavaScript, and here is how this can and should be done:

The ADF Faces af:serverListener component allows developers to invoke server side Java from JavaScript and thus can be used as a proxy to bypass applied client side security.

For example, to be able to change the readOnly property on an af:inputText component, you define the text field as shown below

<af:inputText label="Label 2"
              id="it2" 
              clientComponent="true"                      
              value="#{SetInputTextFieldReadOnly.textValue}">
              <af:serverListener type="serverAction"
                                 method="#{SetInputTextFieldReadOnly.actionEvent}"/>
</af:inputText>

The clientComponent property need to be set to true on the component to ensure a JavaScript object is created on the client architecture. With no clientComponent set to true and no af:clientListener attached, the text field component is not accessible from JavaScript at all.

The af:serverListener needs to be configured on the component that is passed as a component reference to the server. In the sample, the component reference that is sent to the server is the input text field that you want to switch from updateable to read-only. If the integration is from a non ADF Faces component, like an Applet, you would configure the af:serverListener on the af:document component. If this is the case, you may not make use of the component reference on the server and instead pass additional payload arguments.

In the Oracle JDeveloper 11.1.1.6 sample to this article the switch between read-only and updateable is simulated by a command button you can press. The sample can be dowloaded from here.

In a realistic use case, this switch would be triggered from a non ADF Faces component like Applet or another technology you integrate in your ADF Faces page.

Note: The use of a command button in the sample is only for demonstration purpose. If the trigger was a command button then no JavaScript would be needed at all and JavaScript rule #1 would apply

On the server, a managed bean method is invoked by the client JavaScript call shown below:

<af:resource type="javascript">
  function setUpdateable(actionEvent){
     actionEvent.cancel();
     var commandButton = actionEvent.getSource();
     var textFieldId = commandButton.getProperty('componentId');
     invokeServerAction(textFieldId,actionEvent,'true');
  }
       
  function setReadOnly(actionEvent){      
    actionEvent.cancel();
    var commandButton = actionEvent.getSource();
    var textFieldId = commandButton.getProperty('componentId');
    invokeServerAction(textFieldId,actionEvent,'false');
  }   
  function invokeServerAction(compId,evt,isUpdateable){
    var textField = evt.getSource().findComponent(compId);            
    AdfCustomEvent.queue(
         textField,"serverAction",
         {updateable: isUpdateable},false);                              
  }
</af:resource>

Note: payload arguments are surrounded by curly braces. If you want to pass multiple arguments then you use a comma separated list of key1:value1, key2:value2 …pairs.

The JavaScript is taken from the sample provided for this tip and – as mentioned – is invoked from a command button. The command button has a custom property (af:clientAttribute) added that tells the script about the text component Id to modify. The component and the desired switch state "readOnly" or "updateable" is passed to the managed bean method:

 /**
  * Proxy the client request
  * @param clientEvent The client event gives you access to the 
  * component that raises the event as well as to the paraneters 
  * passed from the client to the server 
 */
 public void actionEvent(ClientEvent clientEvent) {
  /*
   * This would be a good place to check an ADF Security resource
   * permission if the user is allowed to perform the change on the 
   * attribute. There is no security in JavaScript, but using server 
   * side JAAS protects you from unauthorized changes
   */
   RichInputText inputText =  (RichInputText) clientEvent.getComponent();
   String updateable = (String) clientEvent.getParameters().get("updateable");
   inputText.setReadOnly(!Boolean.parseBoolean(updateable));
   AdfFacesContext adfFacesContext = AdfFacesContext.getCurrentInstance();
   adfFacesContext.addPartialTarget(inputText);
 }

Sample Download

https://blogs.oracle.com/jdevotnharvest/resource/SetInputTextToReadOnlyJS.zip

Monday Mar 05, 2012

Creating a custom master-detail presentation using af:panelAccordion

ADF Code Corner sample #81 explains how-to create a custom layout to render master-detail information. In the sample ADF Faces panel tabs are used to render the master data and DVT components are used in the panel tabs to show the detail information.

http://www.oracle.com/technetwork/developer-tools/adf/learnmore/81-master-detail-tab-with-graphs-394252.pdf

http://www.oracle.com/technetwork/developer-tools/adf/learnmore/81-master-detail-tab-with-graphs-394253.zip

ADF Code Corner Sample 81

The sample reads master information from the selected panel tab to then – using Java in a managed bean – query the detail record for the DVT component. While the solution documented on ADF Code Corner is efficient, there exists another one that is declarative.

Note: of course there are differences in the usage, but this I'll discuss later

The image below shows an ADF Faces panel accordion that displays the HR schema Departments table information on the accordion tabs and information about contained Employees in a panel box that shows when the accordion is expanded.

MdPresentationWithPanelAccordion

This sample uses an ADF tree binding to render the panel accordion tabs and the contained employee detail information. The iteration is done by two af:forEach tags, as shown below

<af:panelAccordion id="pa1" dimensionsFrom="auto">
 <af:forEach items="#{bindings.allDepartmentsWithEmployees.children}" var="departmentsVar">
   <af:showDetailItem text="#{departmentsVar.DepartmentName}" id="sdi1"
                      stretchChildren="first">
    <af:panelBox text="Employees" id="pb1" showDisclosure="false" type="stretch">
       <f:facet name="toolbar"/>
          <af:panelGroupLayout id="pgl1" layout="scroll">
             <af:forEach items="#{departmentsVar.children}" var="employeesVar">
                 <af:outputText id="ot1"
                                value="#{employeesVar.FirstName} #{employeesVar.LastName}"/>
              </af:forEach>
          </af:panelGroupLayout>
      </af:panelBox>
    </af:showDetailItem>
  </af:forEach>
</af:panelAccordion> 

Note that the departmentVar variable is not accessible within the body of the second af:forEach component. While it can be used to configure the second af:forEach component data access, the variable cannot be referenced from the af:panelBox within the second af:forEach component

As shown in the page source above, the first af:forEach tag reads the parent information from the ADF tree binding. Make sure you set the iterator binding for the tree binding to -1 for the RangeSize property as otherwise you would only see the first 10 parent row. 

(PageDef file)

<executables>
  <variableIterator id="variables"/>
  <iterator Binds="allDepartmentsWithEmployees" RangeSize="-1" DataControl="AppModuleDataControl"
            id="allDepartmentsWithEmployeesIterator" Refresh="deferred"/>
</executables> 

Sample Download

You can download the Oracle JDeveloper 11g R2 (11.1.2.1) sample from here. Just configure the database connection to point to an Oracle database with the HR schema unlocked. The ADF BC model is configured to only show departments that have employees (using a ViewCriteria)

Which solution to choose ?

And Finally, what's the difference between this declarative approach and the  more code centric solution in ADF Code Corner sample 81? The difference is that this sample fetches all data upon rendering of the panel accordion, which may be expensive if we talk about thousands of child (employee) records. The sample on ADF Code Corner queries the detail data when a panel tab is selected. Sample 81 on ADF Code Corner however doesn't cache the data of previously selected panels and thus always re-fetches detail data. When working with large data sets however he solution on ADF Code Corner performs better.

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.

Tuesday Feb 28, 2012

Accessing WebLogic Server JDBC DataSource from Java in JSF

There may be a requirement for you to access a JDBC data source defined on the WebLogic Server (for example to query a database or database schema other than the one the application's business service is connected with.

To access the JDBC DataSource, for example from a managed bean in JSF, you code like the following:

java.sql.Connection
connection = null;
try {
  javax.naming.Context initialContext = new javax.naming.InitialContext();
  javax.sql.DataSource dataSource = 
            (javax.sql.DataSource)initialContext.lookup("java:comp/env/jdbc/hrconnDS");
  connection = dataSource.getConnection();
  
 } catch(Exception e){
      e.printStackTrace();
      //or handle more gracefully 
 }
In the example above, the JDBC DataSource is defined in WLS as "hrconnDS"

Best practice invoking business services methods from JSF beans

Recently there was an increasing interest on OTN in best practices for invoking methods exposed on the ADF Business Components client interface. There exist two options to access methods exposed on ADF Business Components application modules and view objects from a managed bean through ADF.

  • Call findDataControl(String) on the BindingContext and access the application module to invoke a method exposed on the Application Module or View Object client interface.

  • Create a method binding on a PageDef level that binds to a method exposed on the Application Module or View Object client interface

Speaking of best practices, it’s the second option  to use a method binding on the PageDef file that I recommend for the following reasons

  • ADF is about abstracting the view and controller layer from the business service implementation details. A method binding instead exposes an ID (the name o the binding) to the JSF developer, which they use to access the binding from a managed bean using the OperationBinding API. Signature or name changes of a method exposed on the business service thus don't require a change in the managed bean(s) referencing it. All changes would be applied in metadata.

  • ADF provides the OperationBinding class as an abstraction for business services methods. Configuring business service method access on the PageDef file using method bindings exposes a single and consistent API to application developers.

  • Programmatic access to a method exposed on the business service require more lines of code than accessing the same method through the binding layer

  • Direct business service access violates the recommendation to always work through the ADF binding layer and not to bypass it.

To access a method binding from a managed bean, use the following code

  BindingContext bctx = BindingContext.getCurrent();
  BindingContainer bindings = bctx.getCurrentBindingsEntry();
  OperationBinding operationBinding = 
       bindings.getOperationBinding("name_of_method_binding");
  //optional
  operationBinding.getParamsMap().put("argumentName1",value1);
  operationBinding.getParamsMap().put("argumentName2",value2);
  //invoke method
  operationBinding.execute();
  if (!operationBinding.getErrors().isEmpty()) {
     //check errors
     List errors = operationBinding.getErrors();
     ...
  }
  //optional
  Object methodReturnValue = operationBinding.getResult();


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

Book Review: Do More with SOA Integration: Best of Packt

Packt Publishing released "Do More with SOA Integration: Best of Packt", book that aggregates the knowledge of  eight (!) SOA books into one 650 pages mashup.

Lets start my review with a little problem I had when reading this book: For me it was not easy to identify the audience this book a was written for. The book contains chapters that point towards beginners and others pointing towards experienced SOA experts. Other chapters are more hands-on oriented, indicating they are meant for developers. After reading the whole book, I think that the targeted audience is not to qualify though most chapters address IT architects and project leads who need to expose legacy IT infrastructures to external or who plan a new software project based on SOA.

The book touches on various aspects of SOA and in chapter 1 presents an explains a wikipedia of SOA acronyms and architecture patterns for readers foreign to SOA. If you are not yet SOA savvy then this chapter will prove itself helpful in understanding the rest of the book as these SOA acronyms are used throughout the remainder of the book.

Chapter 2 lists problem statements and solutions that describe what SOA is for and why it is good to adopt it into your IT landscape. "Types of integration" on page 82 had me slowing down in my reading pace as I found it an interesting topic. It introduces important concepts of SOA like service interfaces, brokering and communication. The chapter, as most parts of the book, is about awareness and operates on the theory of things, and less on technical implementation details.

Chapter 3 showed that a best of compilation is not always a smooth reading and started with the mentioning of the Trivadis Integration Architecture Blueprint, making me use Google to learn what this is all about. Turns out that this architecture is the documented combined SOA experience of the Switzerland based Trivadis AG. The blueprint is well introduced in this online article on the Packt Publishing website (Note that you need a user account to read the whole article). To quote from this article written by Guido Schmutz, Oracle ACE Directory for FMW and SOA, working for Trvadis AG:

"The Trivadis Integration Architecture Blueprint indicates how integration architectures can be implemented in practice. It achieves this by representing common integration approaches, such as Enterprise Application Integration (EAI); Extract, Transform, and Load (ETL); event-driven architecture (EDA); and others, in a clearly and simply structured blueprint. It creates transparency in the confused world of product developers and theoretical concepts.

...

The Trivadis Integration Architecture Blueprint shows how to structure, describe, and understand existing application landscapes from the perspective of integration. The process of developing new systems is significantly simplified by dividing the integration architecture into process, mediation, collection and distribution, and communication layers. The blueprint makes it possible to implement application systems correctly without losing sight of the bigger picture: a high performance, flexible, scalable, and affordable enterprise architecture."

As a reader I wished this was explained that way in the book (better the same chapter) along with some words about the relevance and how it helps to do more with SOA integration.

Chapter 5 explains the use of BPEL for integrating services of different systems into a single process. Here, the focus is put on the process flow and less on how to work with BPEL. Example configurations are given for exposing services on TIBCO and webMethods, for exposing Siebel and SAP services for orchestration in BPEL. Briefly the talk is about security (basic authentication) and logging.

Chapter 6 looks at ERP integration between PeopleSoft and Oracle Applications. If you are in the situation in which you need to get the two systems working together, then this chapter is for you. It explains how to create an example BPEL process, how to configure the OA adapter as a partner link and how to transform messages between the two systems. A useful reference shared in this chapter is for the Oracle Applications integration cookbook whitepaper, which you find here. Chapter 6 in my opinion is what I was expecting to find in this book: a real use case for SOA that is explained well to help readers solve a current integration problem.

Chapter 7 is about Enterprise Service Bus (ESB) and actually is a quite good read. It teaches the reason why ESB is needed, as well as the individual components, like Normalized Message Router (NMR) it provides. The idea of abstracting different systems, which may be based on different technologies and protocols, and that in the past may not even be designed for communication to the outside world, spoke to me and made this chapter useful. The uses NetBeans Enterprise Pack  5.5 and 6.0 for its screen shots and examples. The current state of the NetBeans enterprise pack is that SOA components have been removed from native NetBeans and instead should be installed from the Open ESB website:

"The SOA module has been removed from the standard distribution for NetBeans IDE 6.7. To use the SOA functionality with NetBeans IDE 6.7, you need to install GlassFish ESB v2.1 from the OpenESB website."  (src: http://soa.netbeans.org/#downloadsandstatus)

The last release of NetBeans that has SOA on board is NetBeans 6.5. I assume that this change was too late for the book to pick up, but at least it makes it appear dated.

Chapter 8 is about binding containers, which is an interesting read that explains NMR bindings to File, FTP, SMTP and JMS (though some of them needs to be downloaded from the Open ESB site to get them working in NetBeans 5.5 or 6.0). The concepts in this chapter are clearly defined and explained, which I liked. A practical example would have been a great addition.

Chapter 9 is about SOA and Web Service integration that aims for helping readers to get their SOA poject started without getting lost in the architecture's complexity. The chapter starts with pointing out that the vertical market thinking of the past often makes it difficult to integrate existing software solutions into a horizontal solution, where businesses need to access information from different business lines. For example, booking a trip to a foreign country often involves information from several airlines, hotels and rental car companies, accessed from a single front-end that hides the complexity that lies behind. It then introduces e-business patterns suggested by IBM. I didn't quite understand what IBM has to do with it and why there is no standard for it? The introduction of the IBM patterns is like the Trivadis architecture in chapter 3: It just falls into the book with no word of explanation regarding the why and the industry acceptance of it. However, the IBM patterns do a good job in outlining several architecture options to solve a specific integration problem. I liked that the patterns are not related to a specific technology and instead are expressed as blue prints. At its end, the chapter explains the  creation of WSDL files and the WS-I profile to then conclude with creating "hello world" Web Services in Java and .Net. The example of "hello world" at the end is a bit odd, given that this chapter guides you to more more complex things before.

With "Service- and Process-Oriented Approach to Integration Using Web Service", chapter 10 has a similar headline then chapter 9 but is about the Enterprise Service Bus (ESB). This chapter also makes me feel like Bill Murray in "Groundhog Day" from 1993: The problem statement that leads to SOA as a solution is getting introduced to me for the 10th time and I think that I'll have to live with it 4 more times until the end of chapter 14 will release me from this loop. On the positive side, you can read chapters in the order you like and don't miss out the relevance of SOA in today's IT. Chapter 10 nicely spans back to the various connection infrastructure types introduced in chapter 1.The chapter explains the role of the ESB in comparison to a pure Web Service approach for integration and its benefits as a connection infrastructure. The chapter states that as of 2010, when the chapter's original book has been published, there is no common standard definition of ESB (which is a statement that also goes in line with what you find on Wikipedia for ESB) nut that ESB evolve "into a tanglible infrastructure for SOA". The chapter therefore lists criteria to look out for when adopting an ESB to avoid vendor lock-in, which I think is very useful information. ESB advantages listed in the chapter includes scalability, connection to heterogeneous systems, mediation, transformation and routing, as well as orchestration and event notification.Like chapter 9, chapter 10 is a very strong chapter and one you want to read several times as it has so much information and insight to share.

Chapter 11 "Loosely Coupling Services" surprisingly already got me out of the "groundhog day" loop and went straight to the subject. It starts off with the criteria defining coupling of a service, the dependencies a services has to its environment, other services and input data streams. The chapter then continues discussing the Oracle Service Bus and Enterprise Service Bus and service virtualization. The content of the chapter is taken from chapter 4 of the Oracle SOA Suite Developer Guide by Antony Reynolds and Matt Wright. I don't understand though why this chapter was taken from the March 2009 version of the book and not from the 11g R1 version printed in June 2010. This decision remains the secret of Carl Jones the series editor but spoils the whole chapter as I kept of wondering which information else I can find is no longer accurate.

Chapter 12 "Integrating BPEL with BPM using BPM Suite" is another hands-on oriented chapter. The software used in this chapter is Oracle SoA Suite 11g PS2, which is a contrast to the older version used in the previous chapter. The chapter introduces the Oracle BPM Suite and its architecture. Readers learn about JDeveloper as the modelling environment and Metadata Services (MDS), a common repository used by the web based Oracle Business Process Composer to save projects. The hands-on journey actually gets stuck first time at a broken link that should point to the BPM Studion 11g extension. Since the publication of the original book the chapter was taken from, Oracle obviously has remodeled its website. However, the link is no longer needed and you can install the software directly from JDeveloper choosing Help --> check for updates. Then you install the Oracle SOA Composite Editor in a first installment and then BPM Studion (just in this order). Just in case you are interested in BPM I highly recommend "Getting Started with Oracle BPM Suite 11gR1  (ISBN 978-1-849681-68-1) from Packt Publishing. The remainder of the chapter then steps you through building a BPM flow for a travel request and approval scenario that included human workflow.

Chapter 13 "SOA Integratio - Functional View, Implementation, and Architecture" and deals with legacy integration. This chapter actually gets me back to "Groundhog Day" by explaining what SOA is (though it doesn't want to be a primer) and I can see Bill Murray staring at its 6 am alarm listening to "I got you babe". However, though starting with some repetition of what has been said many times earlier in the book, the legacy to SOA chapter provides some good information and methodologies for modernizing existing IT infrastructures. From an Oracle technology perspective it also covers the "why should I use" question for individual Oracle products in the context of SOA, which also is a bit of a sales pitch. All in all, I liked this chapter and the information herein.

Chapter 14 is "SOA Integration - Scenarion in Detail" works through a legacy migration project. Its not hands-on driven, but outlines the roles involved as well as the things to consider when approaching such a project. It should go without explicit mentioning that this chapter also repeats some of what the book explained before. Still, a good read.

So What's my final verdict - "buy" or "no-buy"?

As usually, it depends! Do More with SOA Integration: Best of Packt aggregates content written by people who know SOA. Personally I don't think that this is a book that I would bring to work if I was allowed to bring 3 books to a SOA project (Packt Publishing released other SOA books hat I probably would bring instead).

However, this book is not meant to be a programmer guide and for this reason does need to be brought to a job but should be read before planning the overall SOA infrastructure. By my experience in working with Oracle Application Development Framework (though a completely different topic), architecture decisions are too eagerly made driven by technology, which means that already in the planning stage architecture decisions are constraint or mislead by what is working best from an implementation point of view. Here this book really helps you to step back and focus on what you want and then how to achieve it.

My general expectation towards a book is that it enable me to do what I wasn't able to do before and that they provide information I did not know before, raising my awareness for good, best and recommended practices. From this perspective I can recommend this book (on an amazon.com rating scale I would give it 4 stars for the content, -1/2 star for dated information, missed out information and old screen shots and -1/2 for the bumpy reading experience = 3 stars). Note that on the real amazon.com website I found an existing 5 start rating for this book, which may mean I had the wrong glasses on)

Finally, and my apologies to Packt Publishing for stating this, "best-of" book compilations just don't work. Music best-of compilations are easy to listen to. However, best-of compilations of technical books are hard to read without the original chapter authors to add corrections and updates to the previously published content. The Do More with SOA Integration: Best of Packt book contains unnecessary repetitions, references old (out of date) technologies and introduces SOA core technologies in a non-chronological order that takes from the overall reading experience. An example for the latter is the introduction of a "hello world" Web Service at the end of chapter 9, which beside of this is a strong chapter that I liked. If you have money to spend on a single SOA book, my recommendation would be to buy one of the books the chapters were taken from. If you need a single quick overview at a glance and don't mind repetition and older information, still this book is a good reading (but never be 5 star. Again my apologies to Packt Publishing for having to say this; I know you had good in mind)


Thursday Feb 23, 2012

How-to define a default action for page fragments

The af:form component has a DefaultCommand property that, when set to the component Id of a command component like af:commandButton invokes the associated command action when the enter key is pressed anywhere in this form. However, if the form fields are contained in a page fragment exposed in a region then using the DefaultCommand property may not be an option as it is difficult to predict the command button id and its surrounding naming containers.

A solution to this is to use JavaScript on the UI input components that, when the Enter key is pressed virtually press a button within the page fragment (note that the af:form element belongs to the parent page and that you can only have a single af:form component per browser page)

Let's assume a page fragment with a single input text component and a command button to press:

<af:panelFormLayout id="pfl1">
  <f:facet name="footer">
     <af:commandButton text="Print Field Value" id="cb1" partialSubmit="true"                                            
                       clientComponent="true" action="#{View1Bean.onButtonPressed}"/>
   </f:facet>
   <af:inputText label="Enter Field" id="it1" binding="#{View1Bean.inputTextField}">
      <af:clientListener method="onFieldEnterKey" type="keyUp"/>
   </af:inputText>  
</af:panelFormLayout>

The command button is bound to a managed bean action method. By default, the action method is invoked when users press the command button. However, with the JavaScript shown next, this can be simulated and mapped to the Enter key press in the text field.

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:af=http://xmlns.oracle.com/adf/faces/rich
          xmlns:f="http://java.sun.com/jsf/core">

<af:resource type="javaScript">
   //function called by the client listener

  function onFieldEnterKey(inputEvent){
    if (event.getKeyCode() == AdfKeyStroke.ENTER_KEY) {
      //get the input text component from the event            
      var inputTextField = inputEvent.getSource();
      //the button is relative to the input text field so
      //relative search will do with no worrying about naming
      //containers
      var defaultButton = inputTextField.findComponent('cb1');
      //perform a partial submot
      var partialSubmit = true;
      AdfActionEvent.queue(defaultButton,partialSubmit);
      //Enter key does not need to go to server as we
      //queued a new event
       event.cancel();
   }
}
</af:resource>

For JavaScript to work, note the use of the af:clientListener on the input text field and the use of the clientComponent="true" configuration on the button.

Strategies for controlling the af:popup close event

In a previous OTN Harvest summary, I discussed how to handle the af:dialog OK and Cancel event: http://www.oracle.com/technetwork/developer-tools/adf/learnmore/77-ok-cancel-support-in-dialog-351871.pdf . In this post, I get back to this though not covering the "Cancel" case.

There are two options developers have to handle the "Ok" event of an af:dialog component in an af:popup

· Using a DialogListener with the default Ok button

· Using a custom command button instead of the default Ok button

The sample use case is quite simple: A command button added to a page opens the popup component that contains a dialog with an input text field in it. Users can provide a value in the input text field and press either a "custom Ok" button or the default "Ok" button to submit the value and close the popup. In both cases, the provided value in the text field is evaluated and if it is not "ADF ROCKS" written in whatever case, an error message is displayed and the popup is not closed.

Example 1: Using the default OK button and a DialogListener

The sample application opens with a single command button visible on the screen. Pressing the command button uses an af:showPopupBehavior behavior tag to open the popup.

Typing "Hello World" into the text field and pressing the Ok button (which is the default Ok button configured in the Type property of the af:dialog component) invokes a managed bean method that is configured as the DialogListener for the dialog component.

<af:dialog
  …
  binding="#{DialogContentHandler.dialogComponent}"
  contentWidth="300"
  contentHeight="200"
  dialogListener="#{DialogContentHandler.onDialogAction}">

Note that the binding property is set to define a JSF component binding of the dialog to the managed bean to allow the lookup of the input text field in Java. Because the entered text is not "ADF ROCKS", an error message is displayed below the input field To display error messages in a popup, the af:message tag is added to the popup dialog as shown below


<af:dialog …>
  <af:panelFormLayout id="pfl1">
    <af:panelLabelAndMessage label="Validate Me" id="plam1">
     <af:panelGroupLayout id="pgl1" layout="vertical">
        <af:inputText id="it1"/>
          <af:message id="m1" for="it1"/>
        </af:panelGroupLayout>
      </af:panelLabelAndMessage>
  </af:panelFormLayout>
</af:dialog>

The dialog listener managed bean code displaying the error or, in the case of the correct entry, dismissing the dialog is shown next:

/**
 * Dialog Listener that validates the input field for ADF ROCKS. 
 * If the string doesn't match, an error message is shown
 * 
 * @param dialogEvent
 */
public void onDialogAction(DialogEvent dialogEvent) {  
  //lookup the text field starting from the dialog component for
  //which a JSF component binding has been created
  UIComponent inputText = dialogComponent.findComponent("it1");
  String inputTextValue = 
                (String)((RichInputText)inputText).getValue();        
  //If the dialog outcome is OK (the OK button has been pressed)
  //validate the entry
  if(dialogEvent.getOutcome() == DialogEvent.Outcome.ok){
     if(inputTextValue != null &&
         inputTextValue.equalsIgnoreCase("ADF ROCKS")){   
     //ensure the input text value is reset for a second run
     ((RichInputText) inputText).resetValue();
  }
  else{
   //show error message so that popup doesn't close
   FacesContext fctx = FacesContext.getCurrentInstance();
   FacesMessage fm = 
             new FacesMessage(FacesMessage.SEVERITY_ERROR,
                     "Value Validation Failed", "Try: ADF ROCKS");       
   fctx.addMessage(inputText.getId(), fm);
  }
 }
} 

Example 2: Using a custom command button

The af:dialog component renders without default buttons when the Type property is set to none. This is useful if you want to add your own command buttons, which then also are better to customize.

<af:dialog id="…" …>
  <f:facet name="buttonBar">
    <af:commandButton text="Custom OK" id="cb2"                                                  
        action="#{DialogContentHandler.onOK}"                                                    
        partialSubmit="true"/>
</af:dialog>

The use case is the same as before and a message displays when the input text field value is not ADF ROCKS. The only difference to the code executed in a DialogListener is that the command button action listener needs to explicitly close the dialog

public String onOK() {      
  UIComponent inputText = dialogComponent.findComponent("it1");
  String inputTextValue = (String) ((RichInputText)inputText).getValue();
  if(inputTextValue != null &&
     inputTextValue.equalsIgnoreCase("ADF ROCKS")){
     RichPopup rp = (RichPopup)
     dialogComponent.getParent();
     //reset input text component
     ((RichInputText)inputText).resetValue();
     rp.hide();
  }
  else{
    FacesContext fctx = FacesContext.getCurrentInstance();
    FacesMessage fm = 
         new FacesMessage(FacesMessage.SEVERITY_ERROR,
                         "Value Validation Failed", "Try: ADF ROCKS");
         fctx.addMessage(inputText.getId(), fm);
  }        
  return null;
}

Sample Download

You can download an Oracle JDeveloper 11g R2 sample workspace from here: https://blogs.oracle.com/jdevotnharvest/resource/PreventPopupFromClosing.zip. The JSF page has both approaches,default Ok button and custom Ok button on a single dialog. You don't need a database for running the sample.


        
    
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