Pages

Sunday, February 3, 2008

re-use components with ADF Taskflow

With ADF Taskflow you can make page fragments or pages with navigation and re-use this many times in your own applications. Build ones and implement many times. Oracle is doing this too with the webcenter components. These webcenter taskflows are isolated litte programs with its own page fragements and model. If you want to make your own re-usable taskflows then you have to know some things. In this blog I will explain the things you should know. First you have to create a fusion web application. You can ignore the adfc-config.xml this is an unbounded taskflow. Unbounded taskflow don't have a fixed beginning and ending, so it can't be used for the ADF library jar. You have to create a bounded taskflow. There are three different bounded taskflows. The first is the page fragments option. You can use page fragments to add functionality to your page. For example you make a customer info page fragment and include this on the order page or in your marketing application. The others two bounded taskflows are a bit different. This is the train taskflow ( A train is a wizard to help the user to complete the transaction ) and the other is the normal taskflow with pages and methods like a logon flow or a order entry flow. With these two options you have to leave your page and the taskflow pages are shown and when you are ready then you can return to your page.
First we create a bounded taskflow with page fragments. We open this taskflow and add a view from the taskflow menu. Create a page fragment on this view.


<?xml version="1.0" encoding="windows-1252" ?>
<adfc-config xmlns="http://xmlns.oracle.com/adf/controller" version="1.2">
<task-flow-definition id="page1">
<default-activity>page1</default-activity>
<view id="page1">
<page>/page1.jsff</page>
</view>
<use-page-fragments/>
</task-flow-definition>
</adfc-config>

The next step is to create a bounded taskflow without the option page fragements.
Here we also can create a view but now we create a page and we also create a taskflow return. Between the view and the return we add a flowcase with the name return.



<?xml version="1.0" encoding="windows-1252" ?>
<adfc-config xmlns="http://xmlns.oracle.com/adf/controller" version="1.2">
<task-flow-definition id="page">
<default-activity>startpage</default-activity>
<input-parameter-definition>
<name>param1</name>
<value>#{pageFlowScope.inputParam1}</value>
<class>java.lang.String</class>
</input-parameter-definition>
<view id="startpage">
<page>/page.jspx</page>
</view>
<task-flow-return id="return">
<outcome>
<name>return</name>
</outcome>
</task-flow-return>
<control-flow-rule>
<from-activity-id>startpage</from-activity-id>
<control-flow-case>
<from-outcome>return</from-outcome>
<to-activity-id>return</to-activity-id>
</control-flow-case>
</control-flow-rule>
</task-flow-definition>
</adfc-config>

Open the jsf page and add a button with an action "return" else we can't go back to original page. To make this more interesting we add an input parameter to this taskflow and display the parameter on the jsf page.
It is very important to give the page, taskflow and the package name unique names else you can get errors that it finds for example two datacontrols in the same package location or it uses the wrong page.
The last step is to create an ADF library jar deployment profile. This deployment profile add all the bounded taskflows to the jar. This jar you can add as library to other fusion web applications. When you do this and you create or open a jsf page then in the component panel your new taskflow are displayed.

Now you see there are two types. Taskflow and Regions, Regions are the taskflows with the page fragments option.
When you drag one of your region taskflows on the jsf page is gives you the option to create a (dynamic) region. You see the page fragment on your page. Jdeveloper adds the following code to the jsf page
<af:region value="#{bindings.page11.regionModel}" id="page11"/>
and this code to the pagedef
<executables>
<taskFlow id="page11"
taskFlowId="/WEB-INF/page1-task-flow-definition.xml#page1"
xmlns="http://xmlns.oracle.com/adf/controller/binding"/>
</executables>
You can also drag your own taskflow to the page. What now happens depends if the jsf page is part of an unbounded taskflow or not. If so then jdeveloper create a button with an action <af:commandButton text="page" action="page1"/> and update the unbounded taskflow. It adds a taskflow call and a control flow case.



<?xml version="1.0" encoding="windows-1252" ?>
<adfc-config xmlns="http://xmlns.oracle.com/adf/controller" version="1.2">
<view id="portal">
<page>/portal.jspx</page>
</view>
<task-flow-call id="page1">
<task-flow-reference>
<document>/WEB-INF/page-task-flow-definition.xml</document>
<id>page</id>
</task-flow-reference>
<input-parameter>
<name>param1</name>
<value>#{'hello'}</value>
</input-parameter>
</task-flow-call>
<control-flow-rule>
<from-activity-id>portal</from-activity-id>
<control-flow-case>
<from-outcome>page1</from-outcome>
<to-activity-id>page1</to-activity-id>
</control-flow-case>
</control-flow-rule>
</adfc-config>

JDeveloper automatically detects the input parameters.
If you don't use the unbounded taskflow (adfc-config.xml) then jdeveloper create a gobutton with a destination. The value is adf.task-flow?_id=page&_document=/WEB-INF/page-task-flow-definition.xml . If you want to add parameters to this url you have to add param1=hello param1 is the parameter of my taskflow. You can also add a return url by adding _return-url. Here an example of the gobutton. <af:goButton text="page" destination="adf.task-flow?_id=page&amp;_document=/WEB-INF/page-task-flow-definition.xml&amp;param1=hello&amp;_return-url=/webcenter_portal-ViewController-context-root/faces/portal2.jspx"/>
That's all

12 comments:

  1. Hello Edwin,

    Were you able to create and use reusable ADF Libs?

    I tried and failed. My lib is produced from a project containing a simple bounded task flow with a single page fragment. This jsff merely contains an output text component.

    After adding the library to another project, I can see the region in the component palette. I dragged it onto a page and the region was created properly. I could even see the output text (greyed out) on the visual editor.

    However, when I run the page, I get an error
    "WARNING: Error trying to include:viewId:/test-flow-definition/testFlow uri:/testFlow.jsff
    javax.servlet.ServletException: Error in servlet
    "

    I am at my wits end.. Is this reusability documented somewhere?

    ~ Bijesh

    ReplyDelete
  2. Hi Biju,

    I will also test it , did you use tp3 or tp4.

    thanks

    ReplyDelete
  3. Hi Edwin,

    You may or may not know this but I'll give it a shot anyway.

    I'm trying to create a region dynamically in my pages backing bean and attach a regionModel to it that I'm retrieving from a binding that I've already created. Essentially what I want to do is dynamically display a taskflow in different spots on the page depending on the user logging in.

    I can retrieve the regionModel just fine but when I attach it to the RichRegion component and then put the RichRegion inside a container component, nothing shows up. Any thoughts ?

    Thanks,
    Mark

    ReplyDelete
  4. Hi Mark,

    Can you send me a testcase

    thanks Edwin

    ReplyDelete
  5. Hi Edwin,

    I have a problem when trying to reuse a taskflow in another application.

    The taskflow involves pages with bindings. I deployed as an ADF Library Jar and included it in my master application.

    When I run my master application it starts up just fine and I can find the ApplicationModule from the datacontrol (required for my usecase). When I close the browser and start a new session, the DCDataControl returns as null. It has something to do with the taskflow because when I take out the ADF Library Jar, it works just fine again.

    Any thoughts on this ?

    Mark

    ReplyDelete
  6. Hi Mark,

    Do you have a package name problem, you can't have two datacontrol's in the same package name.

    and did you export your connection with the adf lib.

    else please send me a testcase biemond at gmail dot com

    thanks Edwin

    ReplyDelete
  7. Well see the thing is. I don't want to find the app module of the taskflow application, I want to find the main app module.

    I did up a quick test case and it works (no idea yet why my other application doesn't work) but in the testcase it always returns the app module that is inside the ADF library jar as the default.

    They have different packages.

    I'll send you this testcase.

    Mark

    ReplyDelete
  8. Hey, very good article. I wonder about one thing, I need to reuse an inline frame placed in task flow (page fragment) which use a file sevlet to display pdf from server. Is it possible to make servlet avalible in adfLib (in region), becouse now i get only error: "Failed access to redirected secure URL"

    Thank in advance.

    Pawel

    ReplyDelete
  9. Hi,

    for servlets in an ADF library, you need to configure the web.xml and I don't thing ADF will merge this with the viewcontroller project web.xml

    so you need to add this servlet reference to the webcontroller project web.xml, the java classes can still be in the ADF library

    thanks

    ReplyDelete
  10. Thanks for replay.
    I think this solution have sense but still i dont know how to do it. As I said I have ADFLib with jsp page fragment that contains inline frame. For that inline frame, src parameter is a servlet (FileViewServlet) which is configured in web.xml and mapped on java class (url pattern is /file/*). The question is how to create references to this ADFLib servlet in main application that use it?

    Thanks,
    Pawel

    ReplyDelete
  11. Forget about the last comment:)
    I was able to set a reference to this servlet.

    Enough to create a clear reference to the servlet class in ADFLib identical to that which already existed there. Earlier i had a mistake.

    Thanks for your help.

    Pawel

    ReplyDelete