I need to bookmark or deep link a page in an ADF application, either to save a link to the page or share the page by email or other means. Unlike a normal web-app, JSF does not play well with bookmarks, but ADF comes bundled with (somewhat limited)support for doing this. This sort of a requirement is common when we need to include an application link in a generated email report to enable to user to see additional interactive information or to secure the information itself by sending not the report but just a link to it, so that he user will authenticate before accessing the information.
The solution
ADF has bookmark support for pages in the unbounded task flow, so we take a look at how the bookmark attribute works and how to use it. The built in support has limitations in that only pages in the unbounded taskflow can be bookmarked, and at times we would want pages within a bounded taskflow to be bookmark-able, so we take a look at a method for bookmarking/deep-linking a page within a bounded taskflow.
The following example of the out-of-the-box support for bookmarking is based on the standard Oracle documentation here.
You start out with a standard app, in this case a page that lists the departments in the HR schema and a second page that displays the details of the staff in a given department. We need to make this second page bookmark-able, i.e. we need the ability to directly give a URL with parameters and pull the staff information of the department that we use as the parameter in the URL. The taskflow is simple and is shown below.
click to enlarge |
You can download the full example for the complete code, but the essentials of the example are these :
- The first page lists the depatments table, and the second page gets the staff details for a specific department
- The second page is using a sql query (ViewObject) that has the departmentName as a bind parameter.
- You have the first page(welcome) with the department list(from DEPARTMENTS table in HR schema) displayed on a table, and each row has an <af:commandButton> that has its action attribute set to a navigation rule that directs the flow to the staff details page.
- The <af:commandButton> also takes care of passing the parameter to the details page.(code below)
click to enlarge |
Now, for the purpose of the example, the command button has an action listener that is bound to a custom method on the AM that takes the department name as a method parameter and executes the Staff Details VO(this dept name being a bind param for the VO). An <af:setActionListener> sets the dept name corresponding to the button in to a backing bean property. Then in the pageDef for the Department page, an operation binding for the AM method(via DataControl) created and is configured to pickup the backing bean property as a parameter to the AM method. So when the button is clicked:
- The <af:setActionListener> copies the respective department name to a backing bean property
- Then the actionListener for the button fires executing the method binding,
- The method binding takes the department name from the backing bean property(set in step 1), and uses it as a parameter to the AM method.
- This AM method in turn executes the StaffdetailsVO binding the given department name to it.
- Now the staff details VO contains the staff information for the given department.
click to enlarge |
AM Method - click to enlarge |
Then, since the action attribute of the command button was set to a navigation rule to the staff page, the Staff Details page loads displaying the staff VO that has been executed already.
click to enlarge |
This is the basic working of the example app. Now for bookmarking, we need the ability to extract the URL parameter from the URL and execute the StaffDetailsVO when loading the Staff Details page. ADF provides exactly this.
In the unbounded taskflow, open the property inspector for the view activity representing the staff detail page(Click on the StaffDetail ViewActivity) and you can see there is a properties section for bookmarking.
click to enlarge |
Here you will see the URL parameter name and value. They basically mean that the framework will take whatever value is in the URL for the given name, and it will populate that value to the destination. The optional method property lets you invoke a custom method after the values have been processed and before the page is loaded to do custom processing, like execute a VO with the param we get from the URL !
In this case, name is set to “dept” and value is set to #{pageFlowScope.deptDetails.departmentName}, which is the departmentName property in the backing bean. So essesntially what the framework does is look at the URL for the parameter named “dept”, take the value for tht parameter and populate the value to the backing bean property . Now we also have a custom method defined as #{pageFlowScope.deptDetails.loadDepartmentDetails} which is a method defined in the backing bean as:
click to enlarge |
Since the above method is invoked after processing the parameters, the departmentName property of the backing bean has been set to the value specified by the URL param “dept”. So the call to getDepartment will return the department name that was passed though the URL. The rest is like clockwork, we get the same method binding and execute it. Its worthwhile to note here that the method binding here is created on the Staffdetails page’s pageDef and defaults to the backing bean property departmentName for the department name parameter it needs to execute the Staffdetails VO. So setting the operationBinding parameter manually in this method is not required and is shown for demonstration.
Bounded task-flows are a little bit more tricky and before we dive in to the implementation, consider this: When we say URL accessible, we are essentially saying a publicly available resource reachable by a URL, whereas a bounded taskflow is like a component, which needs a container. So we need a way to make the hidden innards of a bounded taskflow accessible in the form of a URL, with optional parameters. One way to do this to setup/construct the state for a page in the bounded taskflow based on the parameters in the URL that we’ll use. Since pages in bounded taskflows cannot be reached directly(actually they can, but the URL is not human readable and is very snarly) the approach here is to create a "container" page in the unbounded taskflow, and embed our bounded taskflow inside the container as a region. Then we will make that "container" page bookmark-able as described above. This way the clients will always see the "container" page's URL which would be nice and simple too. The bookmark-able page takes the URL parameters and passes them to to the taskflow as taskflow params and the task flow will be constructed so that it can recreate state based on the input parameters. Bounded taskflows do have a property called URL invoke. This enables the taskflow to be invoked with a URL, and is a good option when you want to expose the whole taskflow to be URL accessible, not just a page within the taskflow. We will not look at this option as we are trying to gain access to a specific page/part of a taskflow without going though the taskflow’s normal flow.
About the example
As the example, we’re going to do the exact same app as before, but time as a bounded taskflow with parameters. In the example, we will see the whole flow implemented, from search and details, and this is not necessary in most cases where you want to make a single page of your application bookmark-able/linkable. This is more of a pattern that I have found that will save time, and keeps code consistent. Develop the whole taskflow as bounded and provide the extra “hooks” to parts of your bounded taskflow from the unbounded one. This way, you can reap all the benefits of a bounded taskflow (like reusability, security), and the taskflow consumer can expose parts of the taskflow as URL accessible.
First we design the bounded taskflow. Since this taskflow takes parameters, the taskflow parameters and properties can be set in the property inspector by clicking on the blank area in the taskflow diagram.
click to enlarge |
The taskflow starts with a router which decides which page to see. although this is not required, it demonstrates an approach for structuring task flows that are built for URL accessibility(see the “about the example” box note). The important part is the taskflow parameters, as you can see from the property inspector image above. We’ll see how these parameters are passed to the task flow later on. The router looks at one parameter(viewMode) to decide which page page it wants to show. In the example, it is always the StaffDetails page. Once it determines that the details page is to be loaded, it then invokes a MethodCallActivity, passing the second input parameter, which is the deptName, to the method.
This MethodCallActivity has a page definition/ binding container so that it can invoke the AM method to execute the Deatils VO by passing in the dept Name. To open this pageDef file, right click the MethodCallActivity and choose "Go to Page Definition". Once the VO has been executed, the method call outcome loads the StaffDetails page which simple displays the executed VO as before. To make the page URL accessible, we put a “hook” page in the unbounded taskflow that is Bookmarkable and captures the URL parameters.
click to enlarge |
This page contains the bounded taskflow as a region and passes the URL parameters to the taskflow though the page’s pageDef/binding container.
click to enlarge |
Well that's it. You can download the sample workspace with both approaches here: http://myadfnotebook.googlecode.com/files/Bookmarking_with_ADF.zip
[Built on Jdev 11.1.1.3.0, HR schema]
[Built on Jdev 11.1.1.3.0, HR schema]
To run the example
You can run- welcome.jspx file to see bookmarking in unbounded taskflow
Once the page is run, for URL accessibility you can use URLs of the form :
http://<host>:<port>/Bookmarking_with_ADF-ViewController-context-root/faces/staffDetails?dept=Marketing
You would also notice that when using "Staff Details" button on the welcome page to navigate to the details page, the URL in the browser contains the parameter. Thats right. The name and value pair that was configured works both ways. When navigating to a bookmark-able page, the URL is constructed based on this name/value pair by evaluating the value and putting it on the URL as a named parameter. Just the way the same value is extracted from the URL.
- BoundedFlowContainer.jspx for the bounded task flow technique
Once the page is run, for the bounded flow you can use the URL of the form :
http://<host>:<port>Bookmarking_with_ADF-ViewController-context-root/faces/BoundedFlowContainer?deptName=IT (or any other dept name)
Hi,
ReplyDeleteThanks for this very helpful post. We have similar requirement. Two taskflows (one which displays search results and other taskflow displays the details of the selected result).
The results taskflow is a bounded taskflow which has the URL Invoke property set to "url-invoke-allowed".
I am able to invoke to taskflow independently form the URL :
http://127.0.0.1:7101/Bookmarking_with_ADF-ViewController-context-root/faces/adf.task-flow?adf.tfId=details-bounded-task-flow-definition&adf.tfDoc=/WEB-INF/details-bounded-task-flow-definition.xml&documentName=TestDoc
documentName being the parameter. This is the link which would be bookmarked.
I am trying to find a way to call this form another bounded task flow. I couldn't find a way to programmatically compute this URL. Please let me know if there is a way to invoke this taskflow without hardcoding the URL.
Thanks,
Manjunath
Manjunath,
ReplyDeleteThis is surely possible, and my suggestion is not to use the default URL that ADF cretes for you (like the one in your comment), as you've already found out, its hard to compute this on our own.
What you need is a "hook" that can be easily accessed and you can pass only the parameters you need, documentName in your case, without worrying about anything else.
Take a look at the approach described in the second part of the article,"Bookmarking in bounded task-flows", and you should see a solution. The thing is to keep a "landing page" outside, in the unbounded taskflow, so that you can compute the URL to this page easily, and then invoke your taskflow from that page. You dont have to hard code any of your parameters. The "landing page"/"hook" in the unbounded task flow will be marked bookmarkable and takes the parameters you need through the URL. So the URL would look like
http://localhost:port/context_root/LangingPage?documentName=TestDoc
Then it calls your taskflow and passes those parameters it got from the URL to your taskflow. So you'll never have to compute that complex URL. The code sample for this article should make it clear for you on how to capture parameters in your landing page and pass them on to your bounded taskflow. Let me know if you need more help.
In particular, if you have an ADF taskflow and you are in the middle of a task flow, can you have an external application provide a link back to the page where you came from?
ReplyDeleteVidya,
ReplyDeleteNot sure what you are trying to do, but consider the task flow as a single unit, not a set of pages(its not, unless your taskflow is based on pages and not page fragments).
So if you design your taskflow to handle URL parameters like in the article above, you could use that to re-create state by passing in a parameter.
For example, if there are 5 page fragments in a taskflow, you could pass a parameter to the taskflow like 'Step3' which takes you to a specific page fragment. To do this, use a router as the default activity and execute navigation based on the parameter. You still have to deal with re-creating the state to display that page properly, and that depends on the application. Again, I could not understand what you meant and what you are trying to do here. How does an external application come to play in the middle of your taskflow ? Are you referring to the URL from where a user came to your application or a URL to your application getting sent to an external application ?
Hi,
ReplyDeleteNice post. I have the same requirement to bookmark the ADF application page. Downloaded sample application linked to this post.
My Jdeveloper version is 11.1.1.7.0.
Run the application & it is working fine i.e. showing departments & taking to the staff details page by clicking "Staff Details" button.
But I am facing a problem here. I bookmarked the staff details page. Bookmark URL is as follows: localhost:7101/Bookmarking_with_ADF-ViewController-context-root/faces/staffDetails?_adf.ctrl-state=3pj0t13ib_19&dept=DEV&_afrLoop=26095716099107
When I try to access this from another tab, it giving me "403 - Forbidden" error. If I remove the ADF state parameters (_adf.ctrl-state, _afrLoop) in the above URL then page loading fine.
End user do not wish to remove ADF state parameters from the bookmarked URL. Then how to survive from this "403 - Forbidden" issue ?
Thanks,
Gopal.
Same issue as Gopal.
ReplyDeleteHave any solution or workaround ???
Hi,
ReplyDeleteI got a situation as follows:
I got two Task flow created ( task flow1 and task flow2)
and I have created a third task which I call the Introduction(task3), the jsff got just two buttons.
when I click on button1 from task3, it should route to task flow1 and when click on button2 it should route to task flow2.
Looks simple, i am new to ADF, plese help me here,
Regards,
Binu
Hi,
ReplyDeleteMy requirement is -
1. get a parameter from URL and execute VOs based on that parameter. then display the results on page.
2. I have follow an approach to create a Bounced task flow with default activity of method call. this method accepts parameter and executes VO. Then jsff activity is called which displays result.
3. I have added this bounded task flow in jspx page as region and bookmarked it.
when I run the jspx page, it keeps on reloading without showing any results in page. In logs i can see that parameter is read and VO is executed.
When i downloaded your application and ran BoundedFlowContainer.jspx page, it was also behaving similar.
Can you please help me understand what is my mistake. I am using JDeveloper 11.1.2.4
Thanks,
Kaushik
Muğla
ReplyDeleteSamsun
Eskişehir
Sakarya
Kars
SLDPOP
Mardin
ReplyDeleteistanbul
Çanakkale
Antep
Elazığ
OFY5İ
whatsapp görüntülü show
ReplyDeleteücretli.show
W5B
görüntülü.show
ReplyDeletewhatsapp ücretli show
7YZB
429F1
ReplyDeleteUşak Evden Eve Nakliyat
Kütahya Parça Eşya Taşıma
Bilecik Parça Eşya Taşıma
Balıkesir Lojistik
Ordu Parça Eşya Taşıma
64A67
ReplyDeleteYalova Evden Eve Nakliyat
Kars Şehir İçi Nakliyat
Bingöl Şehirler Arası Nakliyat
Isparta Şehirler Arası Nakliyat
Rize Parça Eşya Taşıma
Ünye Oto Lastik
Elazığ Evden Eve Nakliyat
Karabük Şehirler Arası Nakliyat
Bolu Parça Eşya Taşıma
1F3ED
ReplyDeleteZonguldak Parça Eşya Taşıma
Ağrı Şehirler Arası Nakliyat
Aksaray Şehirler Arası Nakliyat
Ünye Mutfak Dolabı
Şırnak Şehir İçi Nakliyat
Çerkezköy Çekici
Çerkezköy Çatı Ustası
Yalova Şehirler Arası Nakliyat
Bartın Şehirler Arası Nakliyat
927F2
ReplyDeleteArdahan Parça Eşya Taşıma
Kırklareli Şehirler Arası Nakliyat
Urfa Şehir İçi Nakliyat
İstanbul Parça Eşya Taşıma
Denizli Şehirler Arası Nakliyat
Diyarbakır Parça Eşya Taşıma
Loop Network Coin Hangi Borsada
Isparta Lojistik
Konya Lojistik
DED7D
ReplyDeletetelefonda kadınlarla sohbet
ardahan sohbet chat
bingöl ücretsiz sohbet odaları
sakarya telefonda canlı sohbet
eskişehir bedava sohbet
Tekirdağ Rastgele Canlı Sohbet
bayburt rastgele sohbet
görüntülü sohbet sitesi
Bingöl Kızlarla Canlı Sohbet
4E11A
ReplyDeleteGörüntülü Sohbet Parasız
Threads Beğeni Satın Al
Binance Referans Kodu
Likee App Beğeni Satın Al
Bitcoin Nasıl Çıkarılır
Bitcoin Nasıl Alınır
Kripto Para Madenciliği Nedir
Expanse Coin Hangi Borsada
Twitter Retweet Hilesi
DC3D1
ReplyDeleteuwulend finance
pancakeswap
shapeshift
DefiLlama
poocoin
avalaunch
pancakeswap
dexscreener
bscpad
513E4
ReplyDeletelayerzero
eigenlayer
poocoin
pancakeswap
dexview
uwulend finance
phantom wallet
bscpad
dappradar