JDeveloper's tagline is "productivity with choice". In previous releases this choice merely applied to the various technologies that could be used in each of the ADF layers. With release 11 this has changed. When choosing the "Fusion" technology stack within ADF (ADF Faces, ADF Task Flows and ADF Business Components), there are many new and powerful concepts and techniques available that allow you to build the required functionality in different ways. Concepts like (un)bounded taskflows, page fragments, (dynamic) regions, page templates, declarative components, declarative transaction support, XML Menu Model, ADF Faces Layout Components and ADF Libraries open up a wide range of new possibilities to build the view and controller layers.
These new possibilities imply that new design decisions must be made on how to build the required functionality. This is not a trivial task. Many of the concepts relate to each other, and choosing how to use one concept can have impact on the usage of other concepts. I admit that's pretty vague, but in this new "Core ADF 11" series, we (the JHeadstart team) will try to make this more concrete. In this series we will share with you the experiences, issues, challenges, design considerations, design decisions and best practices that we faced/encountered/developed when building JHeadstart release 11.
Note that we will assume that you have a basic understanding of the new ADF 11 concepts. If this is not the case, we recommend you take the ADF 11 course from Oracle University, or if you prefer self-study, take a look at the ADF Learning Center.
In this first post, we will start at the beginning: you want to build your first "serious" ADF 11 page, and you immediately need to choose: do I create a page or a page fragment, do I base the page (fragment) on a template, and do I put the page in an unbounded or bounded task flow.
This one is easy: we recommend to always use a page template. Design the template whatever way you want but make sure you include all the UI elements that need to be displayed on each and every page. Typical content of a page template include a branding image/application logo, global actions like Home, Help, Log Out, Preferences, the menu of the application (either a tree menu, or various levels of navigation panes like tabs, buttons or lists) and a footer area with for example a copyright message. Use page template attributes to pass in properties that might differ between pages like the page title, and to conditionally show/hide parts of the page template for specific pages. In a later post, we will go into more details on designing page templates.
Note that you can also dynamically change the page template associated with a page at runtime. Instead of hardcoding the page template path, you can use an EL expression that binds to a look and feel bean that contains the current page template path.
Bounded or Unbounded Taskflows
Each ADF 11 web application has one unbounded taskflow, and can have one or more bounded task flows. So, the choice is not so much about using bounded or unbounded task flows, but about putting a JSF page inside the unbounded taskflow, or inside a bounded task flow.
When building transactional applications, bounded task flows have major advantages over unbounded task flows. For a start, bounded task flows support additional features that can be very useful when building transactional applications:
- Save for Later
- Declarative Transaction Support
- Exception Handling
- Own Memory Scope
- Back button handling
In addition, bounded task flows allow you to benefit from concepts well-known in the world of object oriented programming and component-based development. Using bounded task flows:
- you can create truly reusable user interface components through page fragments and regions;
- with a well-defined service contract; through taskflow parameters you can configure the behavior of the taskflow;
- that are loosely coupled; to use a task flow, you only need to know about the available task flows parameters. The internal flow, structure of user interface components and data structures can be changed without any impact on the pages or other taskflows that are using/calling the taskflow.
In short, well-designed bounded task flows have many advantages over the unbounded task flow. We recommend to only use the unbounded task flow for introductionary pages like the home page or a UI shell page when using regions (see below). All application uses cases should be implemented using a bounded task flow. In a later post in this series, we will discuss in more detail how to design your task flows for maximum reusability.
Stand-alone Pages or Page Fragments with (Dynamic) Regions
For your page design, you basically have three choices
- Create stand-alone .jspx pages
- Create .jsff page fragments within a region, and create a shell page for each region that contains the af:region tag.
- Create .jsff page fragments within a region, and create one common UI shell .jspx page, that uses a dynamic region to display the requested region. This is the "One Page Application" model, where the UI shell page is the only .jspx page in the application, and a menu displayed in the shell page is used to set the current region displayed on the page.
Some considerations and implications to take into account for each choice:
- Stand-alone pages are easiest to build and understand, it is like building your app the "10.1.3 way".
- Stand-alone pages offer little reuse, they cannot be used inside regions
- When you are building a menu-driven application, and each menu entry starts a bounded taskflow with stand-alone pages, there is no easy way to abandon the current task flow. When the user wants to leave the current task flow and clicks on another menu entry, nothing will happen! This is because the control flow case to start the taskflow associated with the other menu item is defined in the unbounded task flow, which is not reachable once a bounded taskflow is started. The easy solution is to not use bounded task flows at all. You will lose all the advantages of bounded task flows, but when simplicity is more important to you then reusability, this is a valid choice. We discuss a more sophisticated solution to the "abandon taskflow with stand-alone pages issue" in this post of the ADF 11 Core series.
- When you are using the XMLMenuModel to create your menu, you can associate one focusViewId with each menu item. If you navigate to the page with this view id, the associated menu item will be highlighted automatically. However, if you then navigate to a detail page from the focusViewId page, you loose the menu item highlighting. In this post, we discuss how you can extend the XMLMenuModel to associate multiple pages with one menu item
Static regions with shell page:
- With this design, you leverage the reuse options of bounded task flows with page fragments
- You do not run into the XMLMenuModel multi-page problem, since each menu item is associated with the shell page which remains the same while navigating between the page fragments within the ADF region embedded in the shell page
- You do not run into the "abandon task flow" issue that occurs with stand-alone pages, since the shell pages are all located in the unbounded task flow.
- If you navigate away to another shell page, you need to be aware that ADF will auto-execute some logic to clean up the abandoned task flow of the region in the previous shell page. The actual clean-up logic executed depends on the transaction settings of the task flow. For example, if the task flow started a new transaction, a rollback will be performed. Note that when using shared data controls, the rollback might have a performance impact since already executed queries in other task flows will need to be re-executed as well. In a later post, we will discuss taskflow transaction management in more detail.
With the previous design option, a shell page is created for each ADF region. Typically, all these shell pages will be very thin and very similar: they are based on the same page template that renders the menu and other common page components, the only difference is the name of the ADF region that is embedded in the shell page. In a one page application, we create one UI Shell page and use a dynamic region to display the correct region. Here are the implications:
- Performance increases because partial page rendering can be used to replace the content of the dynamic region, the UI shell page does not need to be reloaded. In our experience, the performance difference is quite significant. However, according to the documentation there is a feature called Partial Page Navigation which would allow for a similar performance when using separate shell pages or stand-alone pages. I did not get this feature to work though.
- The one-page application raises a problem with XMLMenuModel, opposite to the stand-alone pages design: there is only one page used by all menu items. This can be solved by creating a subclass of XMLMenuModel that highlights the correct menu item based on the currently selected region as set in the dynamic region bean. We will discuss this technique in more detail in a future post.
- When using a dynamic region, the parameters for all region task flows can be defined against the dynamic task flow binding in the page definition of the UI shell page. This quickly becomes ugly and unmanageable: one long list of parameters for all task flows in the application. A better approach is to use the parameter map property of the dynamic task flow binding, and reference the parameter map of the current region through the dynamic region bean. This technique is discussed in more detail in this post.
A variation of this implementation is the use of dynamic tabs rather than a dynamic region. This enables multi-tasking for the end user, see this post for more details on the implementation of dynamic tabs.
While JDeveloper makes it easy to later on convert stand-alone pages to fragments, and unbounded task flows to bounded task flows, it is better to make these design decisions upfront. The choices you make have impact on the usage of XMLMenuModel, menu-driven navigation in general, reusability, transaction management and performance.
We recommend to use bounded task flows with page fragments to maximize reusability. While traditional transactional applications are mostly menu-driven, composite, task-oriented user interfaces are likely to become mainstream in the future. When you start building your ADF 11 app today using (dynamic) regions accessible from a menu, you can reuse the same task flows when building more task-oriented user interfaces using the WebCenter and Human Workflow capabilities planned for JDeveloper 11 release 2.