Home » Java » Enterprise Java » ADF: URL Task Flow Call with HTTP POST Method

About Eugene Fedorenko

ADF: URL Task Flow Call with HTTP POST Method

As we know a bounded task flow can be invoked by some URL either directly from a browser or from some external application. This feature is enabled if task flow’s property “URL invoke” is set to “url-invoke-allowed” and it is commonly used in integration projects. Usually clients (or invokers) use HTTP GET method and pass their parameters in the URL. Let’s consider some simple task flow with one required input parameter:
 
 
 
 
 

  <task-flow-definition id="task-flow-definition">    
    <input-parameter-definition id="__23">
      <name id="__24">userName</name>
      <value id="__67">#{requestScope.userName}</value>
      <class id="__63">java.lang.String</class>
      <required/>
    </input-parameter-definition>    
    ...

The task flow can be invoked by the URL like this

http://127.0.0.1:7101/TestApp/faces/adf.task-flow?adf.tfId=task-flow-definition&adf.tfDoc=/WEB-INF/task-flow-definition.xml&userName=xammer

The client uses a simple html form to construct this GET request:

<html>
  <head>    
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  </head>
  <body>
   <form action="http://127.0.0.1:7101/TestApp/faces/adf.task-flow">
   <input type="hidden" name="adf.tfId" value="task-flow-definition"/>  
   <input type="hidden" name="adf.tfDoc" value="/WEB-INF/task-flow-definition.xml"/>  
   <label>     
        User Name 
      <input type="text" name="userName" value="xammer"/>  
   </label>
      <input type="submit" value="Submit"/>
    </form>
    </body>
</html>

And it looks like this:

Screen Shot 2013-08-02 at 5.55.16 PM

Some clients prefer to use HTTP POST method, and moreover this is their requirement:

<html>
  <head>    
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  </head>
  <body>
   <form action="http://127.0.0.1:7101/TestApp/faces/adf.task-flow" method="POST">
   <input type="hidden" name="adf.tfId" value="task-flow-definition"/>  
   <input type="hidden" name="adf.tfDoc" value="/WEB-INF/task-flow-definition.xml"/>  
   <label>     
        User Name 
      <input type="text" name="userName" value="xammer"/>  
   </label>
      <input type="submit" value="Submit"/>
   </form>
   </body>
</html>

And it works fine as well. The URL in this case is going to look like this:

http://127.0.0.1:7101/TestApp/faces/adf.task-flow

All other necessary information like task flow id and parameter value is inside POST request. But the problem is that it works fine for R1 only. If we try it out on R2 we will get the following:

ADF_FACES-30179:For more information, please see the server’s error log for an entry beginning with: The UIViewRoot is null. Fatal exception during PhaseId: RESTORE_VIEW 1.

Why? Because of that:

oracle.adfinternal.controller.application.InvokeTaskFlowException: ADFC-02006: A task flow ID is not found in the URL.
    at oracle.adfinternal.controller.util.UrlParams.getTaskFlowInfo(UrlParams.java:144)
    at oracle.adfinternal.controller.application.RemoteTaskFlowCallRequestHandler.
invokeTaskFlowByUrl(RemoteTaskFlowCallRequestHandler.java:84)
    at oracle.adfinternal.controller.application.RemoteTaskFlowCallRequestHandler.
doCreateView(RemoteTaskFlowCallRequestHandler.java:63)

All necessary data included task flow id which is supposed to be passed inside POST request is lost. Why?  Because of “loopback”. If we discover requests sent from the browser to the server on clicking the Submit button we’ll see the following:

Screen Shot 2013-08-02 at 6.41.27 PM

Screen Shot 2013-08-02 at 6.45.56 PM

So, instead of sending the “honest” response, the server sends some “loopback” script which generates “window id” and sends the following GET request with generated window id. Cool! But all post data is gone. The GET request is absolutely empty.

Fortunately, the framework doesn’t generate any “loopbacks” if the initial POST request has already some “window id”. So, the workaround for our case is to develop a servlet filter, setting the “window id” attribute for our request:

public void doFilter(ServletRequest servletRequest,
                     ServletResponse servletResponse,
                     FilterChain filterChain)
  throws IOException, ServletException
{
  HttpServletRequest r = (HttpServletRequest) servletRequest;
  HttpSession s = r.getSession();

  //May be this is not an initial request and window id has been generated earlier
  //We want all the following requests to work with the same window id 
  //For our use-case this is ok    
  String windowID = (String) s.getAttribute(_WINDOW_ID_KEY);
  if (windowID == null)
  {
    String pathInfo = r.getPathInfo();
    //This is an initial POST request to get access to the task flow
    if (("/adf.task-flow").equals(pathInfo) &&
        "POST".equals(r.getMethod()))
    {
      windowID = WINDOW_ID;
      //Save window id in the session 
      s.setAttribute(_WINDOW_ID_KEY, windowID);
    }

  }

  //Setup attribute for the request
  //This will prevent generating of the loopback
  if (windowID != null)
    r.setAttribute(_WINDOW_ID_KEY, windowID);

  filterChain.doFilter(servletRequest, servletResponse);
}

private static final String __WINDOW_MANAGER_KEY = RichWindowManager.class.getName();
private static final String _WINDOW_ID_KEY = __WINDOW_MANAGER_KEY + "#WINDOW_ID";  
private static final String WINDOW_ID = "wextflow";

Notice, that this filter should stand before “trinidad” filter in the filter chain:

  <filter>
    <filter-name>ExtPostFilter</filter-name>
    <filter-class>com.cs.fusion.core.view.filter.ExtPostFilter</filter-class>
  </filter> 
  <filter>
    <filter-name>trinidad</filter-name>
    <filter-class>org.apache.myfaces.trinidad.webapp.TrinidadFilter</filter-class>
  </filter>
  <filter>
    <filter-name>ServletADFFilter</filter-name>
    <filter-class>oracle.adf.share.http.ServletADFFilter</filter-class>
  </filter>

That’s it!
 

Reference: URL Task Flow Call with HTTP POST Method from our JCG partner Eugene Fedorenko at the ADF Practice blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

and many more ....

 

Leave a Reply

Your email address will not be published. Required fields are marked *

*


Want to take your Java Skills to the next level?
Grab our programming books for FREE!
  • Save time by leveraging our field-tested solutions to common problems.
  • The books cover a wide range of topics, from JPA and JUnit, to JMeter and Android.
  • Each book comes as a standalone guide (with source code provided), so that you use it as reference.
Last Step ...

Where should we send the free eBooks?

Good Work!
To download the books, please verify your email address by following the instructions found on the email we just sent you.