PK HwEoa,mimetypeapplication/epub+zipPKHwEiTunesMetadata.plistv artistName Oracle Corporation book-info cover-image-hash 265902209 cover-image-path OEBPS/dcommon/oracle-logo.jpg package-file-hash 185728336 publisher-unique-id B31974-12 unique-id 598855743 genre Oracle Documentation itemName Oracle® Fusion Middleware Fusion Developer's Guide for Oracle Application Development Framework, 11g Release 1 (11.1.1.7.0) releaseDate 2013-02-28T18:32:36Z year 2013 PKY&,PKHwEMETA-INF/container.xml PKYuPKHwEOEBPS/ad_persist.htm Allowing User Customizations at Runtime

35 Allowing User Customizations at Runtime

This chapter describes how to use the ADF Faces change persistence framework to create JSF pages that users can customize at runtime.

This chapter includes the following sections:

35.1 Introduction to Allowing User Customizations

Certain ADF Faces components have attributes that can be saved for a specific user. For example, the value of the disclosed attribute on a panelBox component can be saved for a specific user during the current session. The myOrders page in the StoreFront module application contains four panelBox components that display order information. By default, they are expanded, as shown in Figure 35-1.


Note:

The query component, which is not discussed in this chapter, can be used to implement saved searches, another type of user customization. For information about the query component, see Chapter 27, "Creating ADF Databound Search Forms." The configuration required for using MDS to store saved searches is discussed in Section 27.2.3, "How to Persist Saved Searches into MDS."


Figure 35-1 panelBox Components are Expanded by Default

MyOrders page with 4 expanded panelBox

However, suppose a user decides to collapse one of the boxes, as shown in Figure 35-2.

Figure 35-2 panelBox Component Remains Collapsed

panelBox Component Remains Collapsed

Because this application is configured to allow user customizations, then during the user's session, anytime that user returns to the page, the Payment Information box remains collapsed. You need only to enable user customizations for the project in order for these changes to be persisted to the user's session.


Note:

The user session begins when the user logs in to the application, and ends when the user leaves the application. It is possible that while using an application, the user could navigate across application boundaries (for example, to a peer application) and thereby leave the application, at which point the user session would end.


Table 35-1 shows the attribute value changes persisted by an ADF Faces application, after you configure the application to allow user customizations.

Table 35-1 Implicitly Persisted Attribute Values

ComponentAttributeAffect at Runtime

panelBoxshowDetail

showDetailHeader

showDetailItem

disclosed

Users can display or hide content using an icon in the header. Detail content will either display or be hidden, based on the last action of the user.

showDetailItem (used in a panelAccordion component)

flex

The height of multiple showDetailItem components are determined by their relative value of the flex attribute. The showDetailItem components with larger flex values will be taller than those with smaller values. Users can change these proportions, and the new values will be persisted.

showDetailItem (used in a panelAccordion component)

inflexibleHeight

Users can change the size of a panel, and that size will remain.

panelSplitter

collapsed

Users can collapse either side of the splitter. The collapsed state will remain as last configured by the user.

panelSplitter

splitterPosition

The position of the splitter in the panel will remain where last moved by the user.

richTextEditor

editMode

The editor will display using the mode (either WYSIWYG or source) last selected by the user.

calendar

activeDay

The day considered active in the current display will remain the active day.

calendar

view

The view (either day, week, month, or list), that currently displays activities will be retained

panelWindow

dialog

contentHeight

Users can change the height of a panelWindow or dialog popup component, and that height will remain.

panelWindow

dialog

contentWidth

Users can change the width of a panelWindow or dialog popup component, and that width will remain.

activeCommandToolbar
Button

commandButton

commandImageLink

commandLink

commandMenuItem

commandNavigationItem

commandToolbarButton

windowHeight

When users change the contentHeight attribute value of a panelWindow or dialog component, any associated windowHeight value on a command component is also changed and will remain.

activeCommandToolbar
Button

commandButton

commandImageLink

commandLink

commandMenuItem

commandNavigationItem

commandToolbarButton

windowWidth

When users change the contentWidth attribute value of a panelWindow or dialog component, any associated windowWidth value on a command component is also changed and will remain.

column

displayIndex

ADF Faces columns can be reordered by the user at runtime. The displayIndex attribute determines the order of the columns. (By default, the value is set to -1 for each column, which means that the columns will display in the same order as the data source). When a user moves a column, the value on each column is changed to reflect the new order. These new values will be persisted.

column

frozen

ADF Faces columns can be frozen so that they will not scroll. When a column's frozen attribute is set to true, all columns before that column (based on the displayIndex value) will not scroll. When you use the table with a panelCollection component, you can configure the table so that a button appears that allows the user to freeze a column. For more information, see the "Displaying Table Menus, Toolbars, and Status Bars" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

column

noWrap

The content of the column will either wrap or not. You need to create code that allows the user to change this attribute value. For example, you might create a context menu that allows a user to toggle the value from true to false.

column

selected

The selected column is based on the column last selected by the user.

column

visible

The column will either be visible or not, based on the last action of the user. You will need to write code that allows the user to change this attribute value. For example, you might create a context menu that allows a user to toggle the value from true to false.

column

width

The width of the column will remain the same size as the user last set it.

table

filterVisible

ADF Faces tables can contain a component that allows users to filter the table rows by an attribute value. For a table that is configured to use a filter, the filter will either be visible or not, based on the last action of the user. You will need to write code that allows the user to change this attribute value. For example, you might create a button that allows a user to toggle the value from true to false.


You can also configure an application so that the value of these attributes can be persisted across sessions using the MDS repository. For example, if the StoreFront module allowed persistence to the MDS repository, then anytime that user entered the application, the Payment Information box would be collapsed.


Note:

Before you can enable persistence to the repository, you must first follow all MDS configuration procedures as documented in the Oracle Fusion Middleware Administrator's Guide.


Along with the automatic persistence available through ADF Faces, you can create your own custom user customization capabilities for the following types of changes:

If you want to create these types of custom user customizations, you need to add code (for example, in an event handler) that will call the APIs to handle the persistence.

Enabling an application to use the change persistence framework requires that you first enable your application to allow user customizations. Part of this process is determining where those changes should be persisted, either to the session or the MDS repository.

If you choose to persist changes to the session, by default all values as shown in Table 35-1 will be saved for the user's session. However if you choose to persist changes to a repository, you must explicitly configure which of these attribute values will be persisted to the repository. Instead of persisting all these attribute values, you can restrict changes so that only certain attribute value changes for a component are persisted, or so that only specific instances of the components persist changes.


Note:

You cannot persist changes to a component that is contained inside (anywhere in the subtree) of af:forEach or af:iterator tags. While such structure results in multiple copies of a component in the view tree, each component has only a single representation in the JSP document. Therefore, customizations of the component cannot be persisted in MDS.


For any applications that persist changes to an MDS repository, when you deploy your application, you must create a metadata archive (MAR) profile in the application's EAR assembly. For more information, see Section 36.3.2, "How to Create Deployment Profiles."

35.2 Enabling Runtime User Customizations for a Fusion Web Application

Enabling an application to allow user customizations (whether for the default changes that some ADF Faces components provide, or for custom capabilities that you create) requires that you configure your application to use the change persistence framework and that you also determine where those changes should be persisted (either the session or the MDS repository).


Note:

If you are planning on persisting changes to the MDS repository, before configuring an ADF Faces application to use change persistence, you must first follow all MDS configuration procedures as documented in the Oracle Fusion Middleware Administrator's Guide.


35.2.1 How to Enable User Customizations

You enable your application to use the change persistence framework by editing the web.xml and adf-config.xml files.

To enable user customizations:

  1. Double-click the web project in your application to open the Project Properties dialog. In the tree on the left, select the ADF View node.

  2. On the ADF View page, select the Enable User Customizations checkbox. If you want the changes to be persisted to only the session, select the For Duration of Session radio button. If you want the changes to persist to the MDS repository, select Across Sessions Using MDS.

  3. If you chose to persist to the repository, you now need to declare each component tag and associated attribute values that you want persisted to the repository (if you chose to persist only to the session, all values will be persisted). For procedures, see Section 35.3, "Configuring User Customizations." After that configuration is complete, you can override those settings on a per component instance basis. For procedures, see Section 35.4, "Controlling User Customizations in Individual JSF Pages."


    Note:

    If you have created custom user customization capabilities as documented in Section 35.5, "Implementing Custom User Customizations," then you also need to declare those attribute values or operations.


35.2.2 What Happens When You Enable User Customizations

When you elect to save changes only to the session, JDeveloper adds the CHANGE_PERSISTENCE context parameter to the web.xml file, and sets the value to session. This context parameter registers the ChangeManager class that will be used to handle persistence. If you instead elect to save the changes to the MDS repository, the value is set to oracle.adf.view.rich.change.FilteredPersistenceChangeManager, as shown in Example 35-1.

Example 35-1 Context Parameter in web.xml Used For Change Persistence

<context-param>
  <param-name>org.apache.myfaces.trinidad.CHANGE_PERSISTENCE</param-name>
  <param-value>
    oracle.adf.view.rich.change.FilteredPersistenceChangeManager
  </param-value>
</context-param>

Tip:

If needed, you can manually set this value to oracle.adf.view.rich.change.MDSDocumentChangeManager, if you do not want any customizations to be restricted based on configurations in the adf-config.xml file or on the individual JSF pages, and you always want the changes to be persisted to the MDS repository and not the session.


When you elect to persist to the repository, JDeveloper also does the following:

  • Adds the following JARs to the class path if they don't exist:

    • javatools-nodep.jar

    • facesconfigmodel.jar

    • taglib.jar

  • Ensures the ADFBindingFilter is registered. If not, it adds the following entry to the web.xml file.

    <filter>
      <filter-name>adfBindings</filter-name>
      <filter-class>oracle.adf.model.servlet.ADFBindingFilter</filter-class>
    </filter>
    
  • Adds another context parameter to web.xml to register the MDSJSPProviderHelper class to handle merging MDS customization documents with the base JSP document, as shown in Example 35-2

    Example 35-2 Context Parameter in web.xml Used For Merging Changes

    <context-param>
      <param-name>oracle.adf.jsp.provider.0</param-name>
      <param-value>oracle.mds.jsp.MDSJSPProviderHelper</param-value>
    </context-param>
    
  • Adds the ADF Faces Change Manager Runtime 11 library to the project.

  • In the adf-config.xml descriptor file, sets the persistent-change-manager element to the MDSDocumentChangeManager, which is the class that will be used to persist the changes. Example 35-3 shows the configuration for persisting to the MDS repository.

    Example 35-3 Registered ChangeManager Class for Restricted Change Persistence

    <persistent-change-manager>
      <persistent-change-manager-class>
        oracle.adf.view.rich.change.MDSDocumentChangeManager
      </persistent-change-manager-class>
    </persistent-change-manager>
    
  • Creates JSF JSP pages as XML documents. For more information, see Section 35.4, "Controlling User Customizations in Individual JSF Pages."

35.3 Configuring User Customizations

If you choose to persist changes to an MDS repository, you must decide which of the attribute values that are by default persisted to the session (as shown in Table 35-1) should also be persisted to the repository. Alternatively, you can configure which changes you do not want persisted.


Tip:

Often, a system administrator is the one to set the configurations in the adf-config.xml. The persist and dontPersist attributes on a component allow page authors to override that setting as needed.


For example, suppose you decide that you don't want the value for the width attribute on columns to be persisted to the repository, but you do want all other default attribute changes for columns to be persisted. You must explicitly set the other default column values that you want to be persisted, and you also must explicitly configure the application to NOT persist the width attribute.


Note:

If you have created custom user customization capabilities as documented in Section 35.5, "Implementing Custom User Customizations," then you must explicitly declare those attribute values or operations as well.


You set (and unset) these values using the overview editor for the adf-config.xml file. Figure 35-3 shows the overview editor where only certain attribute values for the column component will be persisted.

Figure 35-3 Overview Editor for the adf-config.xml File

overview editor of adf-config.xml

Once set, you can override persistence for a specific component on a page. For example, suppose you want to disallow change on the width attribute on only one table's columns. You want the rest of the tables in the application to persist changes to that attribute. You would configure the columns to globally persist changes to the width attribute, but then for that one table, you would override the global configuration directly on the JSF page. For more information, see Section 35.4, "Controlling User Customizations in Individual JSF Pages."


Note:

If you've enabled just session persistence, then all attribute values shown in Table 35-1 will be persisted to the session. There is no way to override this either globally or on an instance.


35.3.1 How to Configure Change Persistence

By default, when you configure your application to use any type of change persistence (that is, to either the session or a repository), the values of all attributes shown in Table 35-1 will always be persisted to the user's session. If you configured your changes to be persisted to a repository, then you must declare the attributes whose values should be persisted to that repository. If there are any values that you don't want persisted, then you need to configure those values as well.

To declare attribute value persistence to a repository:

  1. In the Application Navigator, expand the Application Resources pane, expand the Descriptor > ADF META-INF node, and double-click adf-config.xml to open that file.

  2. In the overview editor, click the View tab.

  3. In the Tags table, select the component whose changes you want to persist (or not persist) to the repository. If the component does not appear in the table, click the Add icon, and select and add it.


    Note:

    The filter rules specified in the adf-config.xml file are applicable only when you have chosen to persist to the MDS repository (see Section 35.2.1, "How to Enable User Customizations"). These rules do not apply for persistence within session scope.

    If persistence fails for any reason, (for example if one of the filter rules fails or the MDS repository errors), then the values will be stored only within the session scope.


  4. The Tag Attributes table displays all the attributes for the selected component whose values can be persisted. Select Persist Changes for all attributes whose values you want persisted. Deselect any if you do not want the values persisted.


Note:

If you are implementing custom user customizations (see Section 35.5, "Implementing Custom User Customizations"), then you will need to edit the adf-config.xml manually to add the configuration. See Example 35-4 for an example on how to configure user customizations.


35.3.2 What Happens When You Configure Change Persistence

When you select the component tags and attribute values to be persisted in the adf-config.xml file, JDeveloper enters tag library information for the components and attributes that are to be persisted. Example 35-4 shows the entry for persisting the value of the disclosed attribute on the panelBox component.

Example 35-4 Registration of Attribute Changes in adf-config.xml

<taglib-config>
  <taglib uri="http://xmlns.oracle.com/adf/faces/rich">
    <tag name="panelBox">
      <attribute name="disclosed">
        <persist-changes>
          true
        </persist-changes>
      </attribute>
...
    </tag>
  </taglib>
</taglib-config>

35.4 Controlling User Customizations in Individual JSF Pages

Once you have enabled your application to use user customizations, you can control user customizations for specific components on the page.

By default, the framework persists changes for all component instances, based on the configuration in the adf-config.xml file. You can override this default behavior by explicitly setting what should be persisted and what should not be persisted on each component instance using the persist and dontPersist attributes.


Note:

The filter rules specified using the persist and dontPersist attributes are applicable only when you have chosen to persist to the MDS repository (see Section 35.2.1, "How to Enable User Customizations"). These rules do not apply for persistence within session scope.

If persistence fails for any reason, (for example if one of the filter rules fails or the MDS repository errors), then the values will be stored only within the session scope.


The following components support the persist and dontPersist attributes:

35.4.1 How to Implement User Customizations on a JSF Page

You can override any globally set persistence configuration for a component using its persist and dontPersist attributes.


Tip:

Often, a system administrator is the one to set the configurations in the adf-config.xml. The persist and dontPersist attributes allow page authors to override that setting as needed.


To implement user customizations on a JSF Page:

  1. Add components to the page, as needed, including components that will be persisting changes.

  2. If you want to persist all persistable attributes for a component:

    1. In the Property Inspector, expand the Advanced section.

    2. Click the drop-down list for the Persist field and choose All Available.

  3. If you do not want to persist any attributes, repeat Step 2 for the Don'tPersist field.

  4. If more than one attribute can be persisted for the component, and you do not want to persist all of them:

    1. Click the drop-down menu to the right of the Persist field and choose Edit to open the Edit Property dialog.

    2. Shuttle any attributes to be persisted from Available to Selected.

  5. If you do not want to persist an attribute value, repeat Step 4 for the Don't Persist field.


Note:

The filter rules specified using the persist and dontPersist attributes take precedence over any adf-config.xml configuration set for global component-level restrictions.

Values specified for the dontPersist attribute take precedence over values specified for the persist attribute. For example, if for a panelBox component you set disclosed as the value for both the persist and dontPersist attributes, the value of the disclosed attribute will not be persisted.

If you set the value of the persist or dontPersist attribute to All Available, then any values entered as choices using the Edit dialog and the shuttle will be ignored and all available attribute values will be persisted or not persisted.


35.4.2 What Happens at Runtime: How Changes Are Persisted and Restored

When an application is configured to persist changes to the session, any changes made during the session are recorded in a session variable in a data structure that is indexed according to the view ID and the component's ID attribute value. Every time the page is requested, in the subsequent create View or Restore View phase, all changes are applied in the same order as they were added. This means that the changes registered through the session will be applied only during subsequent requests in the same session.

When an application is configured to persist changes to the MDS repository, any changes made during the session are recorded by mutating the Document Object Model that MDS maintains for the JSP document behind the view. A JSF phase listener registered by ADF controller triggers a commit on the MDS session during the appropriate lifecycle phase, resulting in the change document being persisted in the MDS store. Every time the page is requested, Oracle's JSP engine seeks the JSP document from an MDS JSP provider, which provides a flattened document after merging the stored changes to the base document. MDS records the change against the unique value of the component's ID attribute.


Tip:

If changes are applied in response to a partial submit of the page (for example, a commandButton with the partialSubmit attribute set to true), the component for which changes are applied must be set as the value for the partialTarget attribute.


Additionally, be aware that when you run the application from JDeveloper in the Integrated WebLogic Server, MDS creates a local file-based repository to persist metadata customizations. Whereas when the application is deployed to a test or production environment, customizations are persisted to the configured MDS repository. For more information about MDS repository configuration, see the Oracle Fusion Middleware Administrator's Guide. For more information about deploying an application, see Section 36.4, "Deploying the Application."

35.4.3 What You May Need to Know About Using Change Persistence on Templates, Regions, and Declarative Components

The way that changes are persisted for components in templates, regions, and declarative components is handled differently, depending on whether the changes are persisted to the session or to the MDS repository. With session persistence, changes are recorded and restored on components against the viewId for the given session. As a result, when the change is applied on a component that belongs to one of these objects (region, page template, or declarative component), that change is applicable only in the scope of the page that uses the object. It does not span all pages that consume the object.For example, suppose you have pageOne.jspx and pageTwo.jspx, and they both contain the region defined in region.jsff, which in turn contains a showDetail component. When pageOne.jspx is rendered and the disclosed attribute on the showDetail component changes, the implicit attribute change is recorded and will be applied only for pageOne.jspx. If the user navigates to pageTwo.jspx, no attribute change is applied.

When you persist changes to the MDS repository, MDS records and restores customizations for a document identified by a combination of the JSP page path and customization name/value configuration setting as set on the customization class (for more information, see Section 34.2.1.1, "Customization Classes"). As a result, for a given page that is rendered, when MDS applies a change on a component withinone of these objects (region, template, or declarative object), it is applicable for all pages that consume the object and that have the same customization name and value as the source page.

In the previous example, assume that the showDetail component uses the ID of myShowDetail. When pageOne.jspx is rendered and the disclosed attribute on the showDetail component changes, the attribute change is recorded for region.jsff (and not the page that consumes it). This change is applied when any page that contains the region is rendered, as long as the ID remains the same.

Additionally, user customizations are allowed through the persistence change manager on components that are direct children of a page template or a declarative component only if the definition of the page template or declarative component is not private. If it is private, the customization is written into the session store.


Note:

The definition of the page template or declarative component is a tag-only, nonbindable attribute. For declarative components, it is af:componentDef. For page templates, it is af:pageTemplateDef.


35.5 Implementing Custom User Customizations

In addition to the user customization capabilities built in to certain ADF Faces components, you can create your own custom user customization capabilities. The change persistence framework supports the following types of user customizations:

To create custom user customizations, you must create a customization class for each type of user customization and then configure your application to use that class. You also need to set up the layers of customization for your application. For more information about both of these procedures, see Section 34.2, "Developing a Customizable Application."

Once those prerequisites are satisfied, you add logic that calls methods on the ADF Faces classes that handle persisting change either to the session or the MDS repository. To handle the change, you create code that uses the APIs from one of the ADF Faces specialized component change classes. For most cases, you add this code to the event handler method on a managed bean associated with the page the persisting component is on. If you want all instances of a component to persist the same change, you need to add this code for each page on which that component appears.

If you are creating a custom component, you can implement user customizations for the component by adding code directly to the custom component class. In that case, you will need to add the code only to the component class, and not once for each instance of the component. For more information, see Section 35.6, "Creating Implicit Change Persistence in Custom Components."

35.5.1 Change Persistence Framework API

To better understand what you need to do to create custom user customizations, it may help to have a deeper understanding of the change persistence and MDS frameworks. When you elect to persist changes to the MDS repository, the change persistence framework works in conjunction with the MDS framework. Where and how the customizations are saved are determined by how you set up your MDS repository, your customization layers, and your customization classes. Details about the MDS framework and the repository and how to use it are covered in Chapter 34, "Customizing Applications with MDS."

The change persistence framework uses the underlying change manager classes from Apache MyFaces Trinidad (in the org.apache.myfaces.trinidad.change package) along with a few ADF Faces-specific classes (in the oracle.adf.view.rich.change package). The instance of the registered ChangeManager class is accessible through the RequestContext object. It is responsible for gathering changes as they are created and added during a request, and then persisting them. The SessionChangeManager class is an implementation of ChangeManager which handles persistence within a session only, while the MDSDocumentChangeManager class is an implementation that persists to the MDS repository only. The FilteredPersistenceChangeManager class is an implementation of ChangeManager that stores the changes that pass the filter rules into the repository using the registered persistence change manager. Any change that does not get persisted to the repository will be persisted to the session when FilteredPersistenceChangeManager is used.

Additional classes are used to describe the changes to a component. You use these APIs to handle persisting any changes to components other than the implicit value changes the ADF Faces framework provides (as shown in Table 35-1). ComponentChange is the base class for all classes used to implement specific changes that act on the JSF component hierarchy, such as adding or removing a facet or a child component. These changes are automatically applied during subsequent creation of the view, in the same order in which they were added. Classes that extend the ComponentChange class and that also implement the DocumentChange interface can directly persist changes to the MDS repository. Classes that do not implement the DocumentChange interface can persist changes only to the session.

Table 35-2 describes the specialized classes that handle specific customizations. If "yes" appears in the Repository column, then the class implements the DocumentChange interface and it can persist changes to the MDS repository.

Table 35-2 Classes Used to Handle Change Persistence

Class NameRepositoryDescription

AddChildDocumentChange

Yes

Adds a child component using document mark up. While applying this change, the child component is created and added to the document.

AttributeComponentChange

No

Changes the value of an attribute.

AttributeDocumentChange

Yes

Changes the value of an attribute.

MoveChildComponentChange

Yes

Moves a child from one container to another.

RemoveChildComponentChange

Yes

Removes a child component.

SetFacetChildComponentChange

No

Adds a child component to the facet using a document markup. While applying this change, the markup will be added to the document.

SetFacetChildDocumentChange

Yes

Adds a child component to a facet. While applying this change, the DOM element corresponding to the child component is added to the document. If the facet doesn't exist, it will be created. If the facet does exist, all of its content will be removed and the new content added.

RemoveFacetComponentChange

Yes

Removes a facet.

ReorderChildrenComponentChange

Yes

Reorders children of a component.


Aside from a ChangeManager class, you may also need to implement and register the DocumentChangeFactory interface with the ChangeManager class. If the DocumentChangeFactory implementation can provide an equivalent DocumentChange for a ComponentChange, the ChangeManager will use it to persist the DocumentChange to the repository.

35.5.2 How to Create Code for Custom User Customizations

You need to add code to handle any explicit changes you want to create, and to configure the components on the JSF page to handle customization. As with the default user customizations, you also must register the custom changes in the adf-config.xml file.


Note:

When the changes are expressible in more than one form, the change must be recorded in the form with highest precedence. For example:

  • Attribute change for a component: The attribute can be specified on the component tag or it can be expressed using the <f:attribute> tag. In a JSF JSP document, <f:attribute> takes lesser precedence over the attribute specified on the component tag. Therefore, the attribute change on the component tag will be recorded for customization.

  • Column header text in a column component: The header text for the column can be specified using either the headerText attribute or using header facet. In this case, the facet component will have precedence.


To create custom user customizations:

  1. Create a managed bean for the page that contains the component.

  2. Add code to the event handler method for the component that will be used to make the change. This code should obtain the component that contains the change. It should then use the component and the appropriate APIs to create, record, and persist the change.

    Example 35-5 shows the code on the action event handler for a command button for a change that will be persisted to the MDS repository. When a user clicks the button, that source graphic file changes. The event handler method accesses the component and changes the source attribute for the graphic. It then calls the private addAttributeChange method, which first uses the component API to record the change, and then uses the AttributeComponentChange class to set the new source attribute value.

    Example 35-5 Persisting Change to the Repository from an Event Handler on a Managed Bean

    public void modifyObjectImage(ActionEvent event) {
           UIComponent uic = event.getComponent().findComponent("oi1");
           String source = "/images/mediumAd.gif";
           uic.getAttributes().put("source", source);
           _addAttributeChange(uic, "source", source);
        }
    .
    .
    .
        private static void _addAttributeChange(UIComponent uic, String attribName, 
                                                Object attribValue) {
            FacesContext fc = FacesContext.getCurrentInstance();
            ChangeManager cm = 
                RequestContext.getCurrentInstance().getChangeManager();
            ComponentChange cc = 
                new AttributeComponentChange(attribName, attribValue);
            apm.addComponentChange(fc, uic, cc);
        }
    

    Note:

    When you persist changes, in addition to explicitly recording a change on the component (which is done in Example 35-5 using uic.getAttributes().put("source", source) method), you must also directly apply the change using the component API, as was done using the private _addAttributeChange(uic, "source", source) method. Applying the change in this way allows the user to see the change in response to the same request. If the change is recorded on the component, then the change will not be seen until a subsequent request.

    Additionally, if you know that the component will always persist to the repository regardless of any restricted change persistence settings, you can instead call the AdfFacesContext.getCurrentInstance().
    getPersistentChangeManager()
    method.


  3. The ChangeManager class provides support for automatically converting an AttributeComponentChange into an AttributeDocumentChange, thereby allowing persistence to a repository. However, if you need to convert another type of change and you use a specialized change manager class that does not implement the DocumentChange class, you need to create a custom DocumentFactory implementation that converts the component change to a document change.


    Note:

    Automatic conversion of AttributeComponentChange into an AttributeDocumentChange assumes that the component attribute is represented as an attribute of the same name on the associated element in the JSPX document.

    Only those attribute values that are expressible in the JSPX document can be persisted using AttributeDocumentChange. In other words, CharSequence, Number, Boolean and ValueExpression are the only supported data types.

    Only values that implement java.io.Serializable can be persisted using AttributeComponentChange.


  4. If you create a custom DocumentFactory implementation, you need to register it with the appropriate change manager class using the following method in your bean:

    public static void registerDocumentFactory(String targetClassName, 
                                               String converterClassName)
    

    Where targetClassName is the name of the ComponentChange class and converterClassNam%e is the name of your DocumentChangeFactory extension that is capable of converting the target ComponentChange into a DocumentChange. The semantics of name for these classes is same as that of getName() in the java.lang.Class class.

  5. If the class you use to create the component change adds a child that has a subtree of components, and you want to persist the changes to the repository, you must create a DocumentFragment to represent the change.

    Example 35-6 shows how to use the AddComponentDocumentChange specialized class to create a DocumentChange object and use a DocumentFragment to represent the change.

    Example 35-6 Converting a ComponentChange Object to a DocumentChange Object

    public void appendChildToDocument(ActionEvent event)
    {
      UIComponent eventSource = event.getComponent();
      UIComponent uic = eventSource.findComponent("pg1");
      // only allow the image to be added once
      if (_findChildById(uic,"oi3") != null)
        return;
      FacesContext fc = FacesContext.getCurrentInstance();
      DocumentFragment imageFragment = _createDocumentFragment(_IMAGE_MARK_UP);
      DocumentChange change = new AddChildDocumentChange(imageFragment);
      ChangeManager apm = AdfFacesContext.getCurrentInstance().getChangeManager();
      apm.addDocumentChange(fc, uic, change);
    }
     private static final String _IMAGE_MARK_UP =
     "<af:objectImage id='oi3' height='100' width='120' " +
         "source='http://www.somewhere.com/someimage.jpg' " +
         "xmlns:af='http://xmlns.oracle.com/adf/faces'/>";
     
    private static DocumentFragment _createDocumentFragment(
        String markUp)
    {
     // prepend XML declaration
      markUp = "<?xml version = '1.0' encoding = 'ISO-8859-1'?>" + markUp;
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      factory.setNamespaceAware(true);
      factory.setValidating(false);
      DocumentBuilder builder;
      try
      {
        builder = factory.newDocumentBuilder();
      }
      catch (ParserConfigurationException pce)
      {
        _LOG.log(Level.WARNING, "Unable to get XML Parser:", pce);
         return null;
      }
      try
      {
        // use a version explicitly with ISO-8859-1 instead
        byte[] markupBytes = markUp.getBytes();
        Document newDoc = builder.parse(new ByteArrayInputStream(markupBytes));
        DocumentFragment fragment = newDoc.createDocumentFragment();
        // add the document's root element to the fragment
        fragment.appendChild(newDoc.getDocumentElement());
        return fragment;
      }
      catch (SAXException se)
      {
        _LOG.log(Level.WARNING, "Unable to parse markup:" + markUp, se);
        return null;
      }
      catch (IOException ioe)
      {
        _LOG.log(Level.WARNING, "IO Problem with markup:" + markUp, ioe);
        return null;
      }
    }
    
  6. Register the user customizations in the adf-config.xml file, as documented in Section 35.3, "Configuring User Customizations." If the custom changes are of any type other than AttributeDocumentChange, you will need to manually edit the adf-config.xml file and indicate that all changes are allowed for the component, as shown in Example 35-7.

    Example 35-7 Custom Registration in adf-config.xml

    <tag name="inputText">
      <attribute name="label">
        <persist-changes>true</persist-changes>
      </attribute>
      <persist-operations>ALL</persist-operations>
    </tag>
    

35.6 Creating Implicit Change Persistence in Custom Components

When you create a custom component, you may decide that you want certain attribute values on that component to be persisted whenever change persistence is enabled in an application. Setting implicit change on a custom component is similar to setting explicit change persistence on existing components. You add code that executes the actual persistence, but instead of you placing that code on a managed bean, that code can be handled directly by the component class. If your component's attribute values are synchronized with the server using events, then you can use the broadcast method to persist the changes. If the attribute value that you want to persist does not use events, then you need to add code in the renderer and component class.

35.6.1 How to Set Implicit Change Persistence For Attribute Values that Use Events

When an attribute value uses events, you need to add code to the component class.

To set implicit change persistence for attribute values that use events:

  1. Open the custom component class java file.

  2. Add code to the broadcast method that will use the specialized class to create a new ComponentChange object and then call the ChangeManager to add the change.

    Example 35-8 shows the code added to the UIXShowDetail class that persists a change to the disclosed attribute. In this case, the AttributeComponentChange class is used.

    Example 35-8 Persisting Change from a Component Class

    public class UIXShowDetail extends UIXComponentBase
    {
      ...
      public void broadcast(FacesEvent event) throws AbortProcessingException
      {
        super.broadcast(event);
        ...
        if (event instanceof DisclosureEvent)
        {
          boolean isDisclosed = ((DisclosureEvent) event).isExpanded();
          setDisclosed(isDisclosed);
          //Record a Change for 'disclosed' attribute
          AttributeComponentChange aa =
           new AttributeComponentChange('disclosed', isDisclosed ? Boolean.TRUE : Boolean.FALSE);
          AdfFacesContext adfContext = AdfFacesContext.getCurrentInstance();
          adfContext.getChangeManager().addComponentChange(getFacesContext(), this, aa);
          ...
        }
      }
      ...
    

35.6.2 How to Set Implicit Change Persistence For Other Attribute Values

When an attribute does not use events, you need to place code in the component's renderer class.

To set implicit change persistence for other attribute values:

  1. Open the custom component's render class java file.

  2. Use the findTypeConstants method, which takes a ClientMetadata instance and use the addPersistedProperty method to mark certain properties as persisted. Example 35-9 shows a code snippet from the renderer class used for the ADF Faces PanelSplitter component, which implicitly persists the splitterPosition attribute value.

    Example 35-9 Method in Component Renderer Class to Implicitly Persist Changes

    // Code snippet from PanelSplitterRenderer.java  
    protected void findTypeConstants(
        FacesBean.Type type,
        ClientMetadata metadata)
      {
        super.findTypeConstants(type, metadata);
        metadata.addRequiredProperty(
          _orientationKey = type.findKey("orientation"));
        metadata.addRequiredProperty(
          _positionedFromEndKey = type.findKey("positionedFromEnd"));
        metadata.addRequiredProperty(
          _disabledKey = type.findKey("disabled"));
        metadata.addRequiredProperty(
          _splitterPositionKey = type.findKey("splitterPosition"));
        metadata.addPersistedProperty(_splitterPositionKey);
      }
    
  3. In the JavaScript component peer class, define the attribute value to be persisted, using the setProperty function. This function needs to be invoked with the attribute name (as defined in the renderer in the previous step), the value, and "true", meaning the value of the attribute will be set. Example 35-10 shows a code snippet from the panelSplitter class that sets the splitter position.

    Example 35-10 Method in Component Class to Implicitly Persist Changes

    // Code snippet from AdfDhtmlPanelSplitterPeer.js file where we set the 
       splitter position
    
      var component = this.getComponent();
     component.setProperty("splitterPosition",position, true);
    // position is the value to be set 
    
PK &%PKHwEOEBPS/adding_security.htm Enabling ADF Security in a Fusion Web Application

30 Enabling ADF Security in a Fusion Web Application

This chapter describes how you can enable ADF Security in the Fusion web application to define resource grants for Oracle Application Development Framework (Oracle ADF) resources and to restrict the user's ability to view web pages associated those resources.

This chapter includes the following sections:

30.1 Introduction to ADF Security

The ADF Security framework is the preferred technology to provide authentication and authorization services to the Fusion web application. ADF Security is built on top of the Oracle Platform Security Services (OPSS) architecture, which itself is well-integrated with Oracle WebLogic Server. While other security-aware models exist that can handle user login and resource protection, ADF Security is ideally suited to provide declarative, permission-based protection for ADF bounded task flows, for top-level web pages that use ADF bindings (pages that are not contained in a bounded task flow), and at the lowest level of granularity, for rows of data defined by ADF entity objects and their attributes. In this document, these specific resources that the ADF Security framework protects are known as ADF security-aware resources.

You enable ADF Security for Fusion web applications when you run the Configure ADF Security wizard, as described in Section 30.3, "Enabling ADF Security." The wizard configures ADF Security for the entire Fusion web application, so that any web page associated with an ADF security-aware resource is protected by default. This means that after you enable ADF Security, your application is locked down so that the pages are considered secure by default.

After you enable ADF Security you must grant users access rights so that they may view the web pages of the Fusion web application. Access rights that you grant users are known as a security policy that you specify for the page's corresponding ADF security-aware resource. Ultimately, it is the security policy on the ADF resource that controls the user's ability to enter a task flow or view a web page.

Because ADF Security is based on Java Authentication and Authorization Service (JAAS), security policies identify the principal (the user or application role), the ADF resource, and the permission (an operation defined by the resource's ADF permission class). For example, the StoreFront module of the Fusion Order Demo application secures the web pages contained by the checkout-task-flow task flow to grant access only to logged-in users (also known as authenticated users). At runtime, the ADF Security framework performs authorization checking against the task flow's security policy to determine the user's right to complete the view operation. In this case, the security policy must grant the view permission to the user if they are to complete the checkout process.

To simplify the task of defining security policies for users and ADF resources, ADF Security defines a containment hierarchy that lets you define one security policy for the ADF bounded task flow and its contains web pages. In other words, when you define the security policy at the level of the bounded task flow, you protect the flow's entry point and then all pages within that flow are secured by the policy it defines. Additionally, instead of granting access to individual users, you group users into application roles and grant the view permission to the role.

Specifically, you will define security policies in the Fusion web application for the following ADF security-aware resources to make web pages accessible to users:

JDeveloper tools support iterative development of security so you can easily create, test, and edit security policies that you create for ADF resources. You can proceed to create test users in JDeveloper and run the application in Integrated WebLogic Server to simulate how end users will access the secured resources. This chapter describes how to configure the repository of user identities and login credentials known as the identity store.


Note:

References to the identity store in this chapter are always in the context of test user identities that you create for the purpose of running in Integrated WebLogic Server. Typically, you would not migrate these users to the staging environment when you deploy to Oracle WebLogic Server, as described in Section 30.9, "Preparing the Secure Application for Deployment."


To avoid a situation where you have enabled ADF Security but have not yet defined security policies to grant access to test users, the Configure ADF Security wizard lets you grant temporary view rights to all existing ADF resources (a view permission grant will be added to the security policy for each ADF resource). This wizard option gives you the choice to disable automatic grants and proceed to define security policies for ADF resources as you create each resource or to enable automatic view grants and gradually replace these grants with security policies that you define. To understand iterative security development choices, see Section 30.2, "ADF Security Process Overview."


Tip:

Before you enable ADF Security and define security policies for the ADF security-aware resources, you will want to understand the rules that govern ADF authorization checking. Understanding these rules will help you to implement the security you intend. For a discussion of these rules, see Section 30.1.2, "Summary of ADF Security."


30.1.1 Integration of ADF Security and Java Security

The ADF Security model for securing Fusion web application resources is not based on the URL mapping of a security constraint as exemplified by the Java EE security model. In actual practice, security constraints are not feasible for securing a JavaServer Faces (JSF) web application where page navigation is not supported by specific page URLs. For example, when the user navigates to the next page in a task flow, the URL remains the same throughout the flow. As each new page is displayed, there is no means to trigger a URL-based security constraint.

Instead, ADF Security implements a Java Authentication and Authorization Service (JAAS) security model. The JAAS model is policy-based since JAAS is built on the existing Java security model and integrates with any JAAS implementation, including the Oracle Platform Security Services (OPSS) implementation of the JAAS service. Whereas applications that utilize URL security constraints are security-unaware because they rely on the Java EE container to manage security, Fusion web applications require an explicit call to the ADF Security framework to authorize access to resources based on user-defined policies. Thus, when you enable ADF Security and define access policies for ADF resources, your application is security-aware.


Note:

Both OPSS and ADF Security are built on the Java security model known as the Java Authentication and Authorization Services (JAAS), which supports the use of custom permissions to protect the resources of the application. To understand the security features of Oracle Platform Security Services, see the Oracle Fusion Middleware Security Guide.


ADF Security simplifies the implementation of a JAAS authorization model. This implementation minimizes the work needed to create a security-aware application by exposing security policies on ADF resources in a declarative fashion and performing authorization checks on these resources at runtime.

The policy store in JDeveloper is file-based and contains a list of entries known as grants, which define the security policy for the ADF resource. The grant entry includes all the permissions granted to the user to perform operations on the protected resource, for instance, accessing a web page associated with an ADF bounded task flow. Permissions are granted in the policy store to an application role principal.

ADF Security expands on the JAAS model by allowing you to define grants using the actions specified by the ADF Security framework permission classes. These classes are specific to the ADF resource and map the actions to an operation supported by the resource. The policy store for the Fusion web application therefore contains grants that specify:

  • One or more permissions that associate an action defined by the resource's permission class with an instance of the ADF resource in the application (currently, only the view action is supported for bounded task flows and page definitions resources)

  • The grantee, which is an application role defined by your application that you populate with member users or, optionally, enterprise roles for whom you wish to confer the same access rights

In the case of entity objects, the permission class defines read, delete, and update actions.

For a description of the ADF permission classes and supported actions, see Appendix C, "Oracle ADF Permission Grants."

30.1.2 Summary of ADF Security

The use of ADF Security enables web applications to easily adjust to real-world business security requirements, because rather than securing paths to application resources, you secure the view operation on ADF resources with JAAS. JAAS-based ADF Security provides:

  • Declarative security support for ADF resources, such as the bounded task flow

    Because Java EE security is URL-based or page-based, it is not possible to have a navigation control without custom code. With ADF Security, you can control whether or not the user can enter a task flow. Thus, a single security policy for a task flow can control access to multiple web pages. Additionally, because declarative security lets you secure the ADF resource, not the access path, you can reuse the ADF resource elsewhere in the application and it will remain secured.

  • Simplified permission assignment by using application roles that allow for the inheritance of permissions

    While Java EE security roles that are used by Java EE security constraints are flat, JAAS permissions are granted to application roles, which can be nested and may be mapped to enterprise roles that the Oracle WebLogic Server domain defines.

  • Utility methods for use in EL expressions to access ADF resources in the security context

    You can use the ADF Security EL expression utility methods to determine whether the user is allowed to perform a known operation. For example, you can determine whether the user is allowed to view a particular task flow.

Additionally, JDeveloper enables you to quickly create test users and passwords to test security in Integrated WebLogic Server. When you are ready to deploy to Oracle WebLogic Server, you can migrate the application-specific authorization policies to the server and the administrator can configure the application to use an LDAP user repository.

Table 30-1 summarizes the effect that enabling ADF Security has on the application and the various ADF security-aware resources. For further discussion about how you can work most effectively with ADF Security, see Section 30.11.4, "Best Practices for Working with ADF Security."

Table 30-1 Summary of ADF Security-Aware Resources

ADF ResourceHow Oracle ADF Enforces SecurityHow to Grant Access

Bounded task flows in all user interface projects

Protected by default. Requires a grant to allow users to enter the bounded task flow.

Define the grant for the task flow.

Do not define grants for individual page definition files associated with the web pages of the bounded task flow.

Page definition files in all user interface projects

Protected by default. Requires a grant to allow users to view the page associated with the page definition.

If the web page is contained by a bounded task flow, define the grant for the task flow.

Define the grant for the page definition only when the web page is not contained by a bounded task flow or when the page is contained by an unbounded task flow.

Note that the unbounded task flow is not an ADF security-aware component and allows no grants.

Entity objects in the data model project

Not protected by default. Requires a grant to prevent access by users.

Define a grant on the entity object to protect data only if you need to control access at the level of the entire data collection. The data displayed by all components in the user interface that reference the protected entity object will be protected.

Use entity-level security carefully. Instead, consider defining security at the level of the entity attribute.

Note that grants in the model project are saved as metadata on the entity object itself and do not appear in the ADF policy store.

Entity object attributes in the model project

Not protected by default. Requires a grant to prevent access by users.

Define a grant on the entity object attribute to protect data when you need to control access at the level of the columns of the data collection. The data displayed by all components in the user interface that reference the protected entity attribute will be protected.

Note that grants in the model project are saved as metadata on the entity object itself and do not appear in the ADF policy store.


30.2 ADF Security Process Overview

You work in JDeveloper when you want to secure the ADF resources of your Fusion web application. ADF Security will protect your application's bounded task flows and any web pages contained in an unbounded task flow. You enable this protection by running the Configure ADF Security wizard and later by defining ADF security policies to define user access rights for each resource.

As you create the user interface for your application, you may run the Configure ADF Security wizard at any time. You may choose to:


Note:

Before you proceed to secure the Fusion web application, you should become familiar with the ADF Security model, as described in Section 30.1.2, "Summary of ADF Security."


The iterative design and test process is supported by a variety of design time tools.

Each time you create a new bounded task flow or ADF page definition file in your user interface projects, the new ADF resource will be visible in the jazn-data.xml file overview editor. You use the overview editor to define security policies for ADF resources associated with web pages for the entire application. You can also use the overview editor to sort ADF resources and easily view those that have no security policy yet defined.

You use another editor to provision a few test users in the ADF identity store. The identity store you create in JDeveloper lets you define user credentials (user ID and password). The editor also displays the relationship between users you create and the application roles that you assign them to for the purpose of conferring the access rights defined by ADF security policies.

At design time, JDeveloper saves all policy store and identity store changes in a single file for the entire application. In the development environment, this is the jazn-data.xml file. After you configure the jazn-data.xml file using the editors, you can run the application in Integrated WebLogic Server and the contents of the policy store will be added to the domain-level store, the system-jazn-data.xml file, while the test users will be migrated to the embedded LDAP server that Integrated WebLogic Server uses for its identity store. The domain-level store allows you to test the security implementation by logging on as test users that you have created.

You access all design time tools for security under the JDeveloper main menu Application > Secure menu, as shown in Figure 30-1.

Figure 30-1 Accessing the ADF Security Design Time Tools

Application - Secure menu options

Design Phase

To enable ADF Security and set up the policy store for the application that you will run in JDeveloper:

  1. Enable ADF Security to allow dynamic authentication and enforce authorization by running the Configure ADF Security wizard.

    When you run the wizard, if you choose to enable only dynamic authentication, skip the remaining design phase steps. The wizard configures files that integrate the security framework with OPSS on Oracle WebLogic Server.

  2. Create an ADF security-aware resource, such as a bounded task flow with constituent web pages (or regions) or a top-level web page (or region) that is designed using ADF bindings.

    Note: After you run the Configure ADF Security wizard, any web page associated with an ADF security-aware resource will be protected. This means that you must define security policies to make the web pages accessible before you can run the application and test security.

  3. Associate the ADF security-aware resource with one or more application roles that you create.

    Application roles you create are specific to the application and let you confer the same level of access to a set of users (also known as member users). In the test phase you will create some users and add them as members to the application roles you created.

  4. Grant view permission to the ADF security-aware resource and each of its associated application roles.

    The grant confers access rights to the application role's member users. Without the grant, the user would not be able to access the ADF security-aware resource. In the test phase, you will create some users and add them to your application roles.

Testing Phase

To provision the identity store and test security using Integrated WebLogic Server:

  1. Create some users and, optionally, create their enterprise roles.

    You will log in to the application using the user ID and password you define. An enterprise role is a logical role that lets you group users and associate these groups with application roles. The enterprise role is not needed for testing. For more information, see Section 30.4.3, "What You May Need to Know About Enterprise Roles and Application Roles."

  2. Associate the users you created and, optionally, the enterprise roles, with one or more application roles.

    A member user may belong to more than one application role when you wish to confer the access right granted to multiple application roles.

  3. Optionally, replace the default login page with a custom login page.

    The default login page generated by the Configure ADF Security wizard cannot utilize ADF Faces components. It is provided only as a convenience for testing ADF security policies. Your custom login page may be designed with ADF Faces components.

  4. Run the application in JDeveloper and access any ADF security-aware resource.

    The first time you attempt to access an ADF security-aware resource, the security framework will prompt you to log in.

  5. Log in and check that you are able to access the page and its resources as you intended.

    After you log in, the security framework checks the user's right to access the resource. For example, if you receive an unexpected 401 unauthorized user error, verify that you have created grants as suggested in Section 30.11.4, "Best Practices for Working with ADF Security."

Preparation for Staging

To prepare the secure application for deployment to Oracle WebLogic Server in a staging or production environment:

  1. Remove any grants to the test-all role for all ADF security-aware resources and replace with grants that you define.

    Because ADF resources are secure by default, developers testing the application will be granted view access only after security policies are defined. The Configure ADF Security wizard gives you the option to generate grants to the test-all role that will make all ADF resources accessible. To avoid compromising enterprise security, you must eventually replace all temporary grants to the test-all role with explicit grants that you define.

  2. Remove all user identities that you created.

    JDeveloper must not be used as an identity store provisioning tool, and you must be careful not to deploy the application with user identities that you create for testing purposes. Deploying user identities with the application introduces the risk that malicious users may gain unintended access. Instead, rely on the system administrator to configure user identities through the tools provided by the domain-level identity management system.

  3. Confirm that the application roles shown in the policy store are the ones that you want an administrator to eventually map to domain-level groups.

  4. Decide whether or not you what to define a security constraint to protect ADF Faces resource files.

    Resource files including images, style sheets, and JavaScript libraries are files that the Fusion web application loads to support the individual pages of the application. These files are not secured by ADF Security, but you can secure their Java EE access paths if you require all users to be authenticated before they can access the application.

  5. Migrate the finalized policy store and credentials store to the target server.

    Application policies and credentials can be automatically migrated to the domain policy store when the application is deployed to a server in the Oracle WebLogic environment. Support to automatically migrate these stores is controlled by the target server's configuration. If Oracle Enterprise Manager is used to perform the deployment outside of JDeveloper, then the migration configuration settings can be specified in that tool. For information about migrating the jazn-data.xml security policies and the cwallet.sso credentials, see the Oracle Fusion Middleware Security Guide.

30.3 Enabling ADF Security

To simplify the configuration process which allows ADF Security to integrate with OPSS, JDeveloper provides the Configure ADF Security wizard. The wizard is the starting point for securing the Fusion web application using ADF Security. The wizard is an application-level tool that, once run, will enable ADF Security for all user interface projects that your application contains.


Note:

Because the Configure ADF Security wizard enables ADF Security for all user interface projects in the application, after you run it, users will be required to have authorization rights to view any web page contained by a bounded task flow and all web pages associated with an ADF page definition. Therefore, after you run the wizard, the application is essentially locked down until you define security policies to grant view rights to the user. For an overview of the process, see Section 30.2, "ADF Security Process Overview."


30.3.1 How to Enable ADF Security

The Configure ADF Security wizard allows you to choose to enable authentication and authorization separately. You may choose to:

  • Enable only user authentication.

    Although ADF Security leverages Java EE container-managed security for authentication, enabling only authentication means that you want to use the ADF authentication servlet to support user login and logout, but that you intend to define container-managed security constraints to secure web pages.

  • Enable user authentication and also enable authorization.

    Enabling authorization means you intend to control access to the Fusion web application by creating security policies on ADF resources.

The ADF Security framework supports these two choices to give you the option to implement Java EE Security and still be able to support login and logout using the ADF authentication servlet. The benefit of enabling the ADF authentication servlet is that the servlet will automatically prompt the user to log in the first time the application is accessed. The ADF authentication servlet also allows you to redirect the user to a defined start page after successful authentication. You will also be able to manage the page redirect when the user logs out of the application. These redirect features provided by ADF Security are not available using only container-managed security.

Note that ADF Security does not perform authentication, but relies on the Java EE container to invoke the configured login mechanism, as described in Section 30.8.4, "What Happens at Runtime: How ADF Security Handles Authentication."


Best Practice:

Because Java EE security constraints cannot interact with the task flow to secure the current page of a task flow, container-managed security is not a useful solution when your application is designed with ADF task flows. When you use ADF task flows, select the ADF Authentication and Authorization option in the Configure ADF Security wizard. This option will allow you to define security policies to protect the task flows of your application.


Because ADF Security delegates authentication to the web container, when you run the Configure ADF Security wizard, the wizard prompts you to configure the authentication method that you want the web container to use. The most commonly used types of authentication are HTTP Basic Authentication and Form-Based Authentication. Basic authentication uses the browser login dialog for the user to enter a user name and password. Note that with basic authentication, the browser caches credentials from the user, thus preventing logout. Basic authentication is useful when you want to test the application without requiring a custom login page. Form authentication allows the application developer to specify a custom login UI. If you choose Form-based authentication, you can also use the wizard to generate a simple login page. The default login page is useful for testing your application with Integrated WebLogic Server.


Note:

Because the generated login page is a simple JSP or HTML file, you will not be able to modify it with ADF Faces components. For information about replacing the default login page with a custom login page that uses ADF Faces components, see Section 30.7, "Creating a Login Page."


To enable ADF Security for the application:

  1. From the Application menu, choose Secure > Configure ADF Security.

  2. In the ADF Security page, leave the default ADF Authentication and Authorization option selected. Click Next.

    When you run the wizard with the default option selected, your application will enforce authorization for ADF security-aware resources. Enforcing authorization for ADF resources means that you intend to define security policies for these resources to make the web pages of your application accessible. Until you do so, all pages that rely on the ADF bounded task flows and ADF page definitions will remain protected.

    The other two wizard options to configure ADF Security should not be used when you want to enable ADF Security. Those options allow you to temporarily disable ADF Security and run your application without security protection, as described in Section 30.10, "Disabling ADF Security."

    Specifically, the first page of the wizard lets you choose among three options, with the default option set to enable ADF Authentication and Authorization, as shown in Figure 30-2:

    • ADF Authentication and Authorization (default) enables the ADF authentication servlet so that you can redirect to a configured web page when the user logs in and logs out. This option also enables ADF authorization to enforce authorization checking against security policies that you define for ADF resources. This option assumes that you will define application roles and assign explicit grants to those roles to manage access to ADF security-aware resources.

    • ADF Authentication enables the ADF authentication servlet to require the user to log in the first time a page in the application is accessed and supports page redirect by mapping the Java EE application root "/" to the a Java EE security constraint that will trigger user authentication. Since the wizard disables ADF authorization, authorization checking is not performed, whether or not security policies exist for ADF resources. Once the user is logged in, all web pages containing ADF resources will be available to the user.

    • Remove ADF Security Configuration disables the ADF authentication servlet and prevents ADF Security from checking policy grants without altering the existing policy store. In this case, you may require users to log in, become authenticated, and test access rights against URL security constraints using standard Java EE security. Note that running the wizard with this option disables fine-grained security against ADF resources.

    Figure 30-2 Using the Configure ADF Security Wizard to Enable Security-Aware Resources

    First page of the ADF Security wizard
  3. In the Authentication Type page, select the authentication type that you want your application to use when the user submits their login information. Click Next.

    A known issue prevents the ADF authentication servlet from working with Basic type authentication and allows a user to access resources after logout. Use form-based authentication instead of basic authentication. For details about this issue, see Section 30.7.7, "What You May Need to Know About ADF Servlet Logout and Browser Caching."

    If you select Form-based Authentication, you can also select Generate Default Pages to allow the wizard to generate a default login and error page. By default the wizard generates the login and error pages at the top level of the user interface project, as shown in Figure 30-3. If you want to change the location, specify the full path relative to the user interface project.

    Figure 30-3 Using the Configure ADF Security Wizard to Generate a Simple Login Page

    Authentication type page of the ADF Security wizard
  4. In the Automatic Policy Grants page, leave the default No Automatic Grants option selected. Click Next.

    When you select No Automatic Grants, you must define explicit grants that are specific to your application. The test-all application role provides a convenient way to run and test application resources without the restricted access that ADF authorization enforces. However, it increases the risk that your application may leave some resources unprotected.

    Alternatively, you can use the wizard to grant to the test-all application role. When you enable grants to the test-all role, you can postpone defining explicit grants to ADF resources until you are ready to refine the access policies of your application. If you decide to enable automatic grants, do not let application development progress too far and the content of the application become well-established before you replace grants to the test-all role with the your application's explicit grants. The explicit grant establishes the necessary privilege (for example, view on a page) to allow users to access these resources. For more information about the test-all role, see Section 30.8.3, "How to Use the Built-In test-all Application Role."

  5. In the Authenticated Welcome page, select Redirect Upon Successful Authentication to direct the user to a specific web page after they log in. Click Next.

    If you leave the Redirect Upon Successful Authentication option unselected, the user will be returned to the page from which the login was initiated. However, when the user presses Ctrl-N or Ctrl-T to open a new browser window or tab, they will receive a 403 or 404 error unless a welcome page definition appears in the application's web.xml file. You can use this option to specify a welcome page so the definition appears in the application's web.xml file.

    Note that if the web page you specify contains ADF Faces components, you must define the page in the context of /faces/. For example, the path for adffaces_welcome.jspx would appear in the Welcome Page field as /faces/adffaces_welcome.jspx.

    For details about specifying other redirect options, see Section 30.7.5, "How to Redirect a User After Authentication."

  6. In the Summary page, review your selections and click Finish.

30.3.2 What Happens When You Enable ADF Security

After you run the Configure ADF Security wizard with the default ADF Authentication and Authorization option selected in the ADF Security page, you will have:

  • Enabled ADF authentication to prompt the user to log in and to allow page redirects

  • Enabled ADF authorization checking so that only authorized users will have access to ADF resources

The wizard updates all security-related configuration files and ensures that ADF resources are secure by default. Table 30-2 shows which files the Configure ADF Security wizard updates.

Table 30-2 Files Updated for ADF Authentication and Authorization

FileFile LocationWizard Configuration

web.xml

/public_html/WEB-INF
directory relative to the user interface project

And, in JDeveloper, in the user interface project under the Web Content-WEB-INF node

  • Defines the Oracle JpsFilter filter to set up the OPSS policy provider. The filter defines settings that indicate that your servlet has special privileges. It is important that the JpsFilter be the first filter definition in the web.xml file.

  • Adds the Oracle adfAuthentication servlet definition to require the user to log in the first time ADF resources are accessed. Note that ADF Security does not itself perform authentication, but leverages Java EE container-managed security for this purpose.

  • When you select the ADF Authentication and Authorization option in the wizard, maps the adfAuthentication servlet to a security constraint that will trigger user authentication dynamically.

  • When you select the ADF Authentication option in the wizard, maps the Java EE application root "/" to the allPages security constraint that will trigger user authentication dynamically.

  • Sets the authentication method for the Login configuration to handle user login.

  • Defines required security roles, including the role valid-users, which is used to trigger the security constraint that enables dynamic authentication.

adf-config.xml

/.adf/META-INF
directory relative to the web application workspace

And, in JDeveloper, in the Application Resources panel of the Applications window under the Descriptors-ADF META-INF node

  • Defines the JAAS security context.

  • Enables the use of ADF Security security policies for authorization checking (the authorizationEnforce parameter in the <JaasSecurityContext> element is set to true).

  • Enables triggering a login dialog in Java SE applications, including ADF Swing applications (the authenticationRequire parameter in the <JaasSecurityContext> element is set to true). This parameter is not used in Fusion web applications. Fusion web applications rely on settings in the web.xml file to enable authentication.

jps-config.xml

/src/META-INF
directory relative to the web application workspace

And, in JDeveloper, in the Application Resources panel of the Applications window under the Descriptors-META-INF node

  • Enables OPSS security services specifically within the JDeveloper design time.

    When you test data model projects using the Oracle ADF Model Tester or run unit tests for security validation this workspace-specific file must be present. Note that this file is not used in the deployed Fusion web application. For example, when you deploy to Integrated WebLogic Server, OPSS security services are enabled by the DefaultDomain/config/fmwconfig/jps-config.xml file.

weblogic.xml

/public_html/WEB-INF
directory relative to the web application workspace

And, in JDeveloper, in the user interface project under the Web Content-WEB-INF node

  • Maps the valid-users security role to an implicit group called users. Oracle WebLogic Server configures all authenticated users to be members of the users group.

jazn-data.xml

./src/META-INF
directory relative to the web application workspace

And, in JDeveloper, in the Application Resources panel of the Applications window under the Descriptors- META-INF node

  • Sets the default jazn.com realm name for the XML identity store that you configure for use with Integrated WebLogic Server.

    You will use this file to store user identities, user groups, and security policies for the ADF Security-enabled application. This file is used during development and enables support for security when running the Oracle ADF Model Tester. However, when you deploy your application, for example, to Integrated WebLogic Server, security policies will be migrated into the configured policy store in the DefaultDomain/config/fmwconfig/system-jazn-data.xml file.


Because authentication is delegated to the web container, the wizard updates the web.xml file to enable authentication by the ADF authentication servlet. It defines servlet mapping for the ADF authentication servlet and adds two Java EE security constraints, allPages and adfAuthentication, to the web.xml file, as shown in Example 30-1.

Example 30-1 ADF Authentication Descriptors in the web.xml FIle

<servlet>
   <servlet-name>adfAuthentication</servlet-name>
   <servlet-class>
        oracle.adf.share.security.authentication.AuthenticationServlet
   </servlet-class>
   <load-on-startup>1</load-on-startup>
</servlet>
...
<servlet-mapping>
   <servlet-name>adfAuthentication</servlet-name>
   <url-pattern>/adfAuthentication</url-pattern>
</servlet-mapping>
...
<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>
<security-constraint>
   <web-resource-collection>
        <web-resource-name>adfAuthentication</web-resource-name>
        <url-pattern>/adfAuthentication</url-pattern>
   </web-resource-collection>
   <auth-constraint>
        <role-name>valid-users</role-name>
   </auth-constraint>
</security-constraint>

Because the allPages constraint maps to the '/' URL, it protects the Java EE application root. This mapping enables the Oracle WebLogic Server web container to trigger user authentication dynamically even before ADF Security is accessed. When the user first accesses the application, it forces the container to challenge the user for the user name and password. Then when the user accesses a page protected by ADF Security, there is no longer a need to authenticate the user and no need to redirect to the ADF authentication servlet.


Note:

You can remove the allPages constraint from the web.xml file if you prefer to provide a login link or button to explicitly trigger login. You could also have a link or button to perform logout. For details about creating a custom component to perform login and logout, see Section 30.7, "Creating a Login Page." If you keep the constraint to allow dynamic authentication, because it covers everything under the Java EE application root, your login page may not display supporting resources at runtime, as described in Section 30.7.3, "How to Ensure That the Custom Login Page's Resources Are Accessible for Explicit Authentication."


Because every user of the application is required to be able to log in, the security constraint defined against the adfAuthentication resource allows all users to access this web resource. As such, the security role associated with the constraint must encompass all users. To simplify this task, the Java EE valid-users role is defined. The weblogic.xml file maps this role to an implicit users group defined by Oracle WebLogic Server. This mapping ensures that every user will have this role because Oracle WebLogic Server configures all properly authenticated users as members of the users group, as described in Section 30.3.7, "What You May Need to Know About the valid-users Role."


Note:

The adfAuthentication resource constraint provides the definition of a single standard URL pattern against the ADF authentication servlet. Your web pages can provide an explicit login or logout link that references the ADF authentication servlet URL pattern. This explicit login scenario is an alternative to generating a simple login form in the Configure ADF Security wizard and relying on ADF authentication to prompt the user to log in. For details about handling the explicit login scenario, see Section 30.7, "Creating a Login Page."


To enable authorization, the wizard updates the adf-config.xml file and sets the authorizationEnforce parameter in the <JaasSecurityContext> element to true, as shown in Example 30-2.

Example 30-2 AuthorizationEnforce Flag Enabled in the adf-config.xml FIle

<JaasSecurityContext 
  initialContextFactoryClass="oracle.adf.share.security.JAASInitialContextFactory"
  jaasProviderClass="oracle.adf.share.security.providers.jps.JpsSecurityContext"
                             authorizationEnforce="true"
                             authenticationRequire="true"/>

When authorization is enabled, the ADF security context gets the user principal from the HttpServletRequest once the user is authenticated by the container. The user submits a user name and password and that data is compared against the data in the identity store where user information is stored. If a match is found, the originator of the request (the user) is authenticated. The user principal is then stored in the ADF security context, where it can be accessed to obtain other security-related information (such as the group the user belongs to) in order to determine authorization rights. For details about accessing the ADF security context, see Section 30.11.3, "Getting Information from the ADF Security Context."

30.3.3 What Happens When You Generate a Default Form-Based Login Page

The wizard-generated login and error pages are simple HTML pages that are added to the top-level folder of your user interface project. The generated login page defines an HTML form that will submit the user's login request with the standard j_security_check action. This action together with form-based authentication, which is the default option for container authentication provided by the wizard, allows the web container to authenticate users from many different web application resources.

The wizard updates the web.xml file to specify Form-based authentication and identify the location of the pages, as shown in Example 30-3.

Example 30-3 Wizard-Generated Login Page Definition Added to in the web.xml FIle

<login-config>
   <auth-method>FORM</auth-method>
   <form-login-config>
       <form-login-page>/login.html</form-login-page>
       <form-error-page>/error.html</form-error-page>
   </form-login-config>
</login-config>

Your application will display the wizard-generated login page from a server-side redirect in response to the unauthenticated user attempting to access a protected resource. This is known as implicit authentication because the redirect to the login page only occurs when user navigates to a page that contains an ADF security-aware resource.

Note that web applications also have a notion of public pages and allow for explicit, as well as implicit authentication. This means that users should be able to log in to the application by clicking a login link before they navigate to secured content. For information about creating and using a login link, see Section 30.7, "Creating a Login Page."

30.3.4 What You May Need to Know About the Configure ADF Security Wizard

The first time you run the Configure ADF Security wizard and enable authentication and authorization, you secure ADF resources at the level of the application. Additionally, you select specific project-level settings for the user interface project, including the authentication type and the authentication welcome. The wizard adds these web application settings to the web.xml file in the project you select. When your application contains multiple user interface projects and web.xml files, you can return to the wizard and configure these settings in the web.xml file for another user interface project that you select.

30.3.5 What You May Need to Know About ADF Authentication

Although Java EE container-managed security defines standard methods for login and logout, the advantage of using ADF authentication is that the same logout works when the application uses Oracle Single Sign-On (Oracle SSO) service.

On the first access to a page that relies on an ADF security-aware resource, if there is no subject defined, OPSS is configured by the JPSFilter to create a subject containing the anonymous user principal and the anonymous-role role principal. With this role principal, the unauthenticated user will be able to access public web pages that are not associated with any ADF security-aware resources (including ADF bounded task flows or page definitions).

In the case of pages associated with ADF security-aware resources, you must explicitly grant view permission to anonymous-role to make the page accessible to the anonymous user. For details about granting privileges to the anonymous user, see Section 30.5.1, "How to Make an ADF Resource Public."

30.3.6 What You May Need to Know About the Built-In test-all Role

The Configure ADF Security wizard lets you enable automatic grants to the built-in test-all application role for the purpose of granting view permission to all ADF security-aware resources in your application. Without a permission grant, either an automatic view grant or an explicit grant that you define, ADF Security authorization checking enforcement would prevent you from being able to run the application and access its resources. You can run the wizard with the test-all application role feature enabled and then gradually replace automatic view grants with explicit grants. Be aware that you must not deploy the application with grants to the test-all application role in place, since this feature makes all ADF resources public. If you choose to enable the built-in test-all application role in the wizard, see Section 30.9.1, "How to Remove the test-all Role from the Application Policy Store," before deploying your application.

30.3.7 What You May Need to Know About the valid-users Role

The valid-users role is a Java EE security role defined by ADF Security to ensure that all users will access the adfAuthentication servlet web resource defined in the web.xml file. The Configure ADF Security wizard updates the weblogic.xml file to map this ADF Security role to the users principal, as shown in Example 30-4. This mapping ensures that every user will have this role, because Oracle WebLogic Server configures all properly authenticated users as members of the users group.

Example 30-4 valid-users Role Mapping in the weblogic.xml FIle

<security-role-assignment>
   <role-name>valid-users</role-name>
   <principal-name>users</principal-name>
</security-role-assignment>

At runtime, the users principal is added automatically to a successfully authenticated subject by OPSS. From a security perspective, the valid-users role supports ADF authentication only in the case where you need to control access to web resources using security constraints alone. The end result of this mapping relies entirely on Java EE security and does not involve JAAS Permissions.

30.4 Creating Application Roles

You create application roles to represent the policy requirements of the application and to define groups of users with the same view permission rights. The application roles that you create in the application policy store are specific to your application. For example, in the context of the work flow, there may be application roles such as fod-customer, fod-productSpecialist, fod-supervisor, and fod-admin, where fod identifies these roles as specific to the Fusion Order Demo application.

At runtime, the access rights are conferred on the user through the application role for which the user is defined as a member. Thus, before you can define security policies, the policy store must contain the application roles that you intend to issue grants to. This can be an application role that you define (such as fod-users) or it can be one of the two built-in application roles defined by OPSS: authenticated-role or anonymous-role. JDeveloper provides the built-in application roles to let you make ADF resources public, as described in Section 30.5.1, "How to Make an ADF Resource Public."

After you create the application role, you will:


Best Practice:

The ADF Security framework enforces a role-based access control mechanism with permissions granted either to application roles or to individual users. Although you may only need to test security and therefore might not need to create groups of users, you should still create application roles (with at least one user member). Later when you define security polices on the ADF resources, the overview editor for the application policy store will allow you to select an application role for the grant.


30.4.1 How to Create Application Roles

JDeveloper lets you add application roles to the policy store of the jazn-data.xml file, which appears in the Descriptors/META-INF node of the Application Resources panel.


Note:

When you create application roles, be sure to add the new application roles to the policy store, not the identity store. Roles that you add to the identity store define enterprise security roles and provide a way to conveniently group users in the identity store. For more details about enterprise roles, see Section 30.4.3, "What You May Need to Know About Enterprise Roles and Application Roles."


To create application roles in the policy store of the jazn-data.xml file, you use the Application Roles page of the overview editor for the jazn-data.xml file. This editor lets you view the relationship between identity store members and the application roles you create.

To create application roles:

  1. From the Application menu, choose Secure > Application Roles.

  2. In the Application Roles page of the jazn-data.xml overview editor, select the policy store for your application from the Security Policy dropdown list.

    The policy store that JDeveloper creates in the jazn-data.xml file is automatically based on the name of your application.

  3. In the Roles list, click the New icon.

  4. In the Name field, enter the name of the role and click any other field to add the application role to the policy store.

  5. If you have already set up test users in the identity store, you can map users and roles, as described in Section 30.6.3, "How to Associate Test Users with Application Roles."

30.4.2 What Happens When You Create Application Roles

When you add an application role to the policy store, JDeveloper updates the jazn-data.xml file located in the src/META-INF directory relative to the application workspace. Application roles are defined in <app-role> elements under <policy-store>, as shown in Example 30-5. Because the policy store <application> element names the application, at runtime all application roles that you create will be visible to your application only. Other web applications may define a policy store with their own set of application roles.

Example 30-5 Application Role Definition in the Policy Store

<policy-store>
     <applications>
         <application>
            <name>StoreFrontModule</name>
            <app-roles>
               <app-role>
                  <name>fod-users</name>
                  <display-name>FOD Users</display-name>
                  <class>oracle.security.jps.service.policystore.
                                                        ApplicationRole</class>
               </app-role>
               ...
            </app-roles>
            <jazn-policy>
              ...
            </jazn-policy>
         </application>
    </applictions>
</policy-store>

30.4.3 What You May Need to Know About Enterprise Roles and Application Roles

An enterprise role is a role that is maintained in the domain identity store (as opposed to an application identity store). Enterprise roles are available to every application deployed in the domain and are therefore also called external roles.

An application role is a role used by a Fusion web application. It is specific to the application, defined by the application policy, and not necessarily known to the Java EE container. Application roles are scoped in the sense that they can contain only users and roles defined in the application. Application roles must be mapped to enterprise roles.

You use the overview editor for the jazn-data.xml file to create enterprise roles to group users that you add to the identity store. You can use this mechanism to assign entire groups of users to application roles that you have defined for the purpose of conferring access rights defined by ADF security policies, as described in Section 30.6.3, "How to Associate Test Users with Application Roles."

However, Integrated WebLogic Server does not require you to create enterprise roles to run the application within JDeveloper. For the purpose of testing the application, it may be sufficient to create a few test users and assign them directly to application roles. When you run the application in JDeveloper, the users and any enterprise roles you defined will be created in the default security provider (which is embedded LDAP for Integrated WebLogic Server).

Typically, when you deploy the application for staging, you will migrate only the policy store to the target server. You can configure JDeveloper deployment options so that the identity store, including test users and enterprise roles, is not migrated, as described in Section 30.8.1, "How to Configure, Deploy, and Run a Secure Application in JDeveloper."

After you deploy the secure application, Oracle Fusion Middleware will merge your application's policy store with the policies of the domain-level policy store. To complete this task, the administrator for the Oracle WebLogic Server will eventually map the application roles of your policy store to the existing domain-level enterprise roles. This application role mapping at the domain level allows enterprise users to access application resources according to the ADF security policies you have defined. The domain-level application role mapping by the administrator also allows you to develop the ADF security policies of your application without requiring any knowledge of the identity store in the production environment.

30.5 Defining ADF Security Policies

Authorization relies on a policy store that is accessed at runtime and that contains permissions that grant privileges to execute predefined actions, like view, on a specified object. Initially, after you run the Configure ADF Security wizard, the policy store defines no grants. And, because the default wizard option ADF Authentication and Authorization enables authorization checking, the web pages of your application that rely on the ADF security-aware resources will be inaccessible to users. You must use JDeveloper to define explicit grants for the resources that you want to permit users to access.


Best Practice:

When you run the Configure ADF Security wizard with the default option ADF Authentication and Authorization selected, you will lock down the web pages of your application. This affords the most protection to the Fusion web application possible since you will define explicit grants to allow users to access only the pages you intend. For a discussion of this guideline and others, see Section 30.11.4, "Best Practices for Working with ADF Security."


Before you can define security policies, the policy store for your application must contain the application roles that you intend to issue grants to. This can be an application role that you define (such as fod-users) or it can be one of the two built-in application roles defined by OPSS: authenticated-role or anonymous-role. You use application roles to classify users, so that each member of the same role possesses the same access rights. As such, the security policy names the application role as the principal of the grant, rather than specific users. For details about defining application roles, see Section 30.4, "Creating Application Roles."

For the user interface project, you use the jazn-data.xml file overview editor to secure ADF resources, including ADF task flows and ADF page definitions. In JDeveloper, you open the editor on the jazn-data.xml file by double-clicking the jazn-data.xml file (located in the Application Resources panel) or by choosing Secure > Resource Grants from the Application menu in the JDeveloper main menu.

Note that when you open the jazn-data.xml file, the overview editor provides additional editor pages that you use to create test users, enterprise roles, and application roles.

For the data model project, you do not secure entity objects or their attributes using the jazn-data.xml file overview editor. Instead, you set metadata directly on these objects to manage whether or not the databound UI component displays the data. For details about granting permissions for row-level security, see Section 30.5.10, "How to Define Policies for Data."

30.5.1 How to Make an ADF Resource Public

It is a common requirement that some web pages be available to all users, regardless of their specific access privileges. For example, the home page should be seen by all visitors to the site, while a corporate site should be available only to those who have identified themselves through authentication.

In both cases, the page may be considered public, because the ability to view the page is not defined by the users' specific permissions. Rather, the difference is whether the user is anonymous or a known identity.

In the ADF Security model, you differentiate between the absence of security and public access to content by granting access privileges to the anonymous-role principal. The anonymous role encompasses both known and anonymous users, thus permission granted to anonymous-role allows access to a resource by unauthenticated users, for example, guest users. To provide access to authenticated users only, the policy must be defined for the authenticated-role principal.


Note:

For details about creating a public home page which contains links to other pages in the application, see Section 30.7.4, "How to Create a Public Welcome Page."


Before you begin:

  1. Create bounded task flows, as described in Section 14.2, "Creating a Task Flow."

  2. Create web pages with an ADF page definition file, as described in Section 12.6, "Working with Page Definition Files."

  3. Run the Configure ADF Security wizard, as described in Section 30.3, "Enabling ADF Security."

  4. Create application roles, as described in Section 30.4, "Creating Application Roles."

To grant public access to ADF security-aware resources:

  1. From the Application menu, choose Secure > Resource Grants.

  2. In the Resource Grants page of the jazn-data.xml file overview editor, select one of the following resources from the Resource Types dropdown list:

    • Task Flow when you want to make a bounded task flow public. The application displays the web pages under the permission you define for the task flow itself. Thus, all constituent web pages of the bounded task flow will become public.

    • Web Page when you want to make individual web pages public. Typically, these pages are defined by an unbounded task flow and are top-level pages in the application, such as a home page.

  3. In the Resources column, select the ADF resource for which you want to grant access rights.

    The resource you select should display the lock icon in the first column next to the resource name. The lock icon indicates that the resource has no security policy defined and therefore is "locked"—which means it remains inaccessible to users until you define a grant. For example, in Figure 30-4, the ADF resource customer-registration-task-flow (a bounded task flow) shows the lock icon since no grant has been made.

    Tip: Click the key toggle icon in the header for the overview editor's first column to hide or show resources that already have grants and display only the resources without grants. The key icon indicates that the resource has a grant that will make the resource accessible to users with sufficient access rights.

    Figure 30-4 Selecting an ADF Security-Aware Resource in the Overview Editor

    Selecting a resource in ADF policy editor
  4. In the Granted to column, click the Add Grantee icon and choose Add Application Role.

  5. In the Select Application Roles dialog, select one of these built-in application roles:

    • anonymous-role means the resource will be accessible to anyone who visits the site. A grant to this role is necessary if you want to make a web page associated with an ADF security-aware resource accessible before a user logs in. For example, you would grant to anonymous-role for a task flow that manages customer registration.

    • authenticated-role means the resource will be accessible only to authenticated users (ones who visit the site and log in). For example, you would grant to authenticated-role for an employee registration task flow.

  6. In the Select Application Roles dialog, click OK.

  7. In the Resource Grants page of the overview editor, in the Actions column, leave the View action selected.

    By default, the overview editor shows view selected, as shown in Figure 30-5. The view action is the only action currently supported for Fusion web applications.

    The actions customize, grant, or personalize are implemented for page definition security in Oracle WebCenter Portal: Framework applications or custom applications that are enabled to use Oracle WebCenter Portal's Composer.

    Figure 30-5 Granting to anonymous-role in the Overview Editor

    Granting to anonymous-role in ADF policy editor

30.5.2 What Happens When You Make an ADF Resource Public

When you define a security policy, the jazn-data.xml file overview editor updates the jazn-data.xml file located in the /src/META-INF node relative to the web application workspace.

The overview editor writes the policy information to the <policy-store> section of the file. The security policy, or grant, contains both a grantee and one or more permissions. The grantee is the application role that the policy is being defined for—in this case, the anonymous role. Each permission defines the resource being secured and the action that can be performed against that resource.

Example 30-6 shows a security policy in the jazn-data.xml file that makes a customer registration task flow public. The grant to anonymous-role contains a single view permission for a bounded task flow, customer-registration-task-flow. With this grant, all users will be able to enter the customer registration task flow and complete the customer registration process. Additional grants to the anonymous role may be made and will appear in the <permissions> section of the anonymous role grant.

Example 30-6 Grants to anonymous-role in the Application-Level Policy Store

<policy-store>
   ...
   <jazn-policy>
      <grant>
         <grantee>
            <principals>
                <principal>
                   <class>oracle.security.jps.internal.core.
                                         principals.JpsAnonymousRoleImpl</class>
                   <name>anonymous-role</name>
                </principal>
            </principals>
         </grantee>
         <permissions>
            <permission>
                  <class>oracle.adf.controller.security.TaskFlowPermission</class>
                  <name>/WEB-INF/customer-registration-task-flow.xml#
                                           customer-registration-task-flow</name>
                  <actions>view</actions>
            </permission>
            ...
         </permissions>
      ...
      </grant>
      ...
   </jazn-policy>
</policy-store>

30.5.3 What Happens at Runtime: How the Built-in Roles Are Used

The anonymous-role and authenticated-role names are special roles defined by Oracle Platform Security Services (OPSS).

When you run the Configure ADF Security wizard, the wizard configures the JpsFilter definition in the web.xml file to enable support for the anonymous role. The enabled anonymous role allows ADF Security to support browsing of the site by anonymous users—those users who have not yet logged in. In contrast, the authenticated role is not declared and is always recognized by default. ADF Security supports both of these roles.

When an end user first accesses an ADF security-aware resource, the system creates a subject and populates it with the anonymous role principal. As long as the ADF security-aware resource being accessed has the view grant to anonymous role, the user is permitted access. If the anonymous role is not a grantee of the ADF resource, the user is prompted to log in. After logging in, the authenticated role is added to the subject. The wizard also adds the JpsFilter definition to the web.xml file, where remove.anonymous.role set to false ensures that the anonymous role principal is available even after the user logs in. With the authenticated role principal, the user may access resources that have an explicit grant to the authenticated role.

30.5.4 How to Define Policies for ADF Bounded Task Flows

You define the access policy for an ADF bounded task flow by creating permission grants in the Resource Grants page of the jazn-data.xml file overview editor overview editor. The grants you create will appear as metadata in the policy store section of the jazn-data.xml file. This metadata defines a permission target (in this case, the bounded task flow definition name) for which you have issued grants to authorize the members of a specific application role.


Best Practice:

Do not create permission grants for the individual web pages of a bounded task flow. When the user accesses the bounded task flow, security for all pages will be managed by the permissions you grant to the task flow. And, because the contained web pages (with associated page definitions) will be inaccessible by default, ADF Security prevents users from directly accessing the pages of the task flow. This supports a well-defined security model for task flows that enforces a single entry point for all users. For further information about implementing security policies, see Section 30.11.4, "Best Practices for Working with ADF Security."


You can sort the task flows in the overview editor by clicking the toggle buttons in the Task Flow header, as described in Table 30-3.

Table 30-3 Resource Grant Toggle Buttons for Bounded Task Flows

ButtonToggle ActionDescription

Task flow with no grants icon


Shows/hides resources with no grants

Represents a bounded task flow with no permission grants defined. The web pages that the task flow calls will not be accessible to any user.

Task flow with grants icon


Shows/hides resources with grants

Represents a bounded task flow with one or more permission grants defined. The web pages that the task flow calls will be accessible to users who are members of the application role that received the grant.


The list of available actions displayed by the overview editor is defined by the task flow permission class (oracle.adf.controller.security.TaskFlowPermission). The permission class maps these actions to the operations supported by the task flow. Table 30-4 shows the actions displayed by JDeveloper for ADF bounded task flows.

Note that the view action is the only action currently supported for Fusion web applications. Do not select customize, grant, or personalize actions—they are reserved for future use in task flow security.

Table 30-4 Secured Actions of ADF Bounded Task Flows

Grantable ActionEffect on the User Interface

view

Controls who can read and execute a bounded task flow in a Fusion web application.

This is the only operation that the task flow supports.

customize

Reserved for future use. This action is not checked at runtime.

grant

Reserved for future use. This action is not checked at runtime.

personalize

Reserved for future use. This action is not checked at runtime.


To define a grant for the task flow security policy, use the Resource Grants page of the overview editor for the jazn-data.xml file.

Before you begin:

  1. Create bounded task flows, as described in Section 14.2, "Creating a Task Flow."


    Best Practice:

    If you are creating bounded task flows in separate UI projects of the same application, you will want to assign unique task flow definition names. This is necessary because a grant's task flow definition name is scoped in the jazn-data.xml policy store by path (for example, /WEB-INF/mytaskflow-definition.xml#mytaskflow-definition). Therefore creating bound task flows with unique definition names is the only way to impose project-level scoping of the grants.


  2. Run the Configure ADF Security wizard, as described in Section 30.3, "Enabling ADF Security."

  3. Create application roles, as described in Section 30.4, "Creating Application Roles."

To define a permission grant on an ADF bounded task flow:

  1. From the Application menu, choose Secure > Resource Grants.

  2. In the Resource Grants page of the jazn-data.xml file overview editor, select Task Flow from the Resource Types dropdown list.

    The overview editor displays all the task flows that your application defines. Task flows are defined by task flow definition files (.xml) that appear in the Web Content/Page Flows node of the user interface project.

  3. In the Resources column, select the task flow for which you want to grant access rights.

    The first time you make a grant to a bounded task flow, the first column should display the Resources without any grants icon (represented by the "lock" icon) next to the task flow name. The overview editor displays the lock icon to indicate that a resource has no security policy defined and therefore is "locked"—which means it remains inaccessible to users until you define a grant.

    Tip: Click the Resources with grants icon (represented by the "key" icon) in the header for the Resources column to hide all task flows that already have grants. This will display only task flows without grants, as shown in Figure 30-6. Additionally, you can type a partial task flow name in the search field to display only the task flows with character-matching names.

    Figure 30-6 Hiding Task Flows with Grants in the Overview Editor

    Hiding task flows with grants in ADF policy editor
  4. In the Granted to column, click the Add Grantee icon and choose Add Application Role.

  5. In the Select Application Roles dialog, select the application role that you want to make a grantee of the permission.

    The Select Application Roles dialog displays application roles from the jazn-data.xml file. It also displays the built-in OPSS application roles, anonymous-role and authenticated-role, as described in Section 30.5.3, "What Happens at Runtime: How the Built-in Roles Are Used."

    If you do not see application roles that are specific to your application, create the role, as described in Section 30.4, "Creating Application Roles."

  6. In the Select Application Roles dialog, click OK.

  7. In the Resource Grants page of the overview editor, in the Actions column, leave the view action selected.

    By default, the overview editor shows view selected, as shown in Figure 30-7. The view action is the only action currently supported for Fusion web applications. Do not select customize, grant, or personalize actions—they are reserved for future use and will not be checked by ADF Security at runtime.

    The TaskFlowPermission class defines task flow—specific actions that it maps to the task flow's operations, as described in Table 30-4.

    Figure 30-7 Granting to an Application Role for a Bounded Task Flow Definition in the Overview Editor

    Task flow grant in ADF policy editor
  8. You can repeat these steps to make additional grants as desired.

    The same task flow definition can have multiple grants made for different application roles. The grants appear in the policy store definition of the jazn-data.xml file, as described in Section 30.5.6, "What Happens When You Define the Security Policy."

30.5.5 How to Define Policies for Web Pages That Reference a Page Definition

You define the access policy for an ADF page definition by creating permission grants in the Resource Grants page of the jazn-data.xml file overview editor. The grants you create will appear as metadata in the policy store section of the jazn-data.xml file. This metadata defines a permission target (in this case, the page definition name) for which you have issued grants to authorize the members of a specific application role.


Best Practice:

Create permission grants for the individual web page only when the page is not a constituent of a bounded task flow. Page-level security is checked for pages that have an associated page definition binding file only if the page is directly accessed or if it is accessed in an unbounded task flow. For further information about implementing security policies, see Section 30.11.4, "Best Practices for Working with ADF Security."


You can sort the web page definition resources in the overview editor by clicking the toggle buttons in the Resources header, as described in Table 30-5.

Table 30-5 Resource Grant Toggle Buttons for Web Page Definitions

ButtonToggle ActionDescription

Page with no grants icon


Shows/hides top-level pages with no grants

Represents a page definition with no permission grants defined for a web page that is contained in an unbounded task flow. The web page will not be accessible to any user.

Page with grants icon


Shows/hides top-level pages with grants

Represents a page definition with one or more permission grants defined for a web page that is contained in an unbounded task flow. The web page will be accessible to users who are members of the application role that received the grant.

Page contained by bounded task flow icon


Shows/hides pages included in a bounded task flow

Represents a page definition associated with a web page that also is contained in a bounded task flow. Do not grant to these web page definitions. Instead, define a security policy for the bounded task flow.

Page with no page definition icon


Shows/hides unsecurable pages (with no page definition)

Represents a web page with no page definition defined that is contained in an unbounded task flow. (Pages like this that are contained by a bounded task flow are secured by the bounded task flow's permission.) The web page will be accessible to all users since it is not secured by an associated ADF security-aware resource. Optionally, you can secure the page by adding an empty page definition file, as described in Section 30.5.8, "What You May Need to Know About Defining Policies for Pages with No ADF Bindings."


The list of available actions displayed by the overview editor is defined by the region permission class (oracle.adf.share.security.authorization.RegionPermission). The permission class maps these actions to the operations supported by the ADF page definition for the web page. Table 30-6 shows the actions displayed by JDeveloper for ADF page definitions.

Note that the view action is the only action currently supported for Fusion web applications. Do not select customize, grant, or personalize actions—they are implemented for page definition security only in Oracle WebCenter Portal: Framework applications.

Table 30-6 Securable Actions of ADF Page Definitions

Grantable ActionEffect on the User Interface

view

Controls who can view the page.

This is the only operation that the page definition supports without the Oracle WebCenter Portal: Framework.

customize

Controls who can make implicit changes (such as minimize/restore, delete, or move) to a WebCenter Portal customizable component (in a Panel Customizable or Show Detail Frame) contained in a page of a custom application (one enabled to use Oracle WebCenter Portal's Composer) or a WebCenter Portal: Framework application. For details, see the Oracle Fusion Middleware Developer's Guide for Oracle WebCenter Portal.

grant

Confers the rights specified by all WebCenter Portal-specific actions combined; it is equivalent to granting all other actions. It also controls who can make grants to other users and who can change security settings on the page using Oracle WebCenter Portal's Composer. For details, see the Oracle Fusion Middleware Developer's Guide for Oracle WebCenter Portal.

personalize

Controls who can make implicit changes (such as minimize/restore, delete, or move) to a WebCenter Portal customizable component (in a Panel Customizable or Show Detail Frame) contained in a page of a custom application (one enabled to use Oracle WebCenter Portal's Composer) or a WebCenter Portal: Framework application. For details, see the Oracle Fusion Middleware Developer's Guide for Oracle WebCenter Portal.


To define a grant for the page definition security policy, use the Resource Grants page of the overview editor for the jazn-data.xml file.

Before you begin:

  1. Create the top-level web pages with an ADF page definition file, as described in Section 12.6, "Working with Page Definition Files."


    Best Practice:

    If you are creating top-level web pages in separate UI projects of the same application, you will want to assign unique page file names. This is necessary because a grant's page definition name is scoped in the jazn-data.xml policy store by package (for example, view.pageDefs.mytoppagePageDef). Therefore creating top-level pages with unique file names is the only way to impose project-level scoping of the grants.


  2. Run the Configure ADF Security wizard, as described in Section 30.3, "Enabling ADF Security."

  3. Create application roles, as described in Section 30.4, "Creating Application Roles."

To define a permission grant on an ADF page definition:

  1. From the Application menu, choose Secure > Resource Grants.

  2. In the Resource Grants page of the jazn-data.xml file overview editor, select Web Page from the Resource Types dropdown list.

    The Resource Grants page of the overview editor displays all web pages, including those that have an associated ADF page definition. This includes any web page that uses ADF data bindings or any web page for which you have created an empty page definition. Page definitions are defined by PageDef.xml files that appear in the Application Sources node of the user interface project.

  3. In the Resources column, select the page definition for which you want to grant access rights.

    The first time you make a grant to a page definition, the first column should display the Resource without any grants icon (represented by the "lock" icon) next to the page definition name. The editor displays the lock icon to indicate that a resource has no security policy defined and therefore is "locked"—which means it remains inaccessible to users until you define a grant. For example, the page definition account_updateUserInfo shown in Figure 30-8 displays the lock icon since no grant has been made. Other page definitions in Figure 30-8 show the Page included in bounded task flow icon because they are not top-level pages and thus are securable by the containing bounded task flow.

    Do not create grants for individual web page definitions that display the Page included in bounded task flow icon. Security policies for the associated web pages are secured by their bounded task flow. For example, in Figure 30-8, the page definition associated with the account_addressDetails.jsff region will be secured by the containing bounded task flow.

    Tip: You can type a partial page definition name in the search field to display only the page definitions with character-matching names. For example, a search on the word account would display only the page definitions that begin with the word account, as shown in Figure 30-8.

    Figure 30-8 Matching Page Definitions by Name in the Overview Editor

    Searching for a web page in ADF policy editor

    Tip: You can click the Resources with grants icon (represented by the "key" icon) to hide all page definitions that already have grants. Confirm that the Show pages included in a bounded task flow toggle button in the header for the Resources column is toggled off to hide all page definitions that are included in a bounded task flow (by default, it is set to hide these pages). This will display top-level pages that have no grants (and unsecurable pages, if any), as shown in Figure 30-9.

    Figure 30-9 Hiding Web Pages with Grants in the Overview Editor

    Hiding pages with grants in ADF policy editor
  4. In the the Granted to column, click the Add Grantee icon and choose Add Application Role.

  5. In the Select Application Roles dialog, select the application role that you want to make a grantee of the permission.

    The Select Application Roles dialog displays application roles from the jazn-data.xml file. It also displays the built-in OPSS application roles, anonymous-role and authenticated-role, as described in Section 30.5.3, "What Happens at Runtime: How the Built-in Roles Are Used,"

    If you do not see application roles that are specific to your application, create the role, as described in Section 30.4, "Creating Application Roles."

  6. In the Select Application Roles dialog, click OK.

  7. In the Resource Grants page of the overview editor, in the Actions column, leave the view action selected.

    By default, the overview editor shows view selected, as shown in Figure 30-10. The view action is the only action currently supported for Fusion web applications. The actions customize, grant, or personalize are implemented for use in Oracle WebCenter Portal: Framework applications or custom applications that are enabled to use Oracle WebCenter Portal's Composer.

    The RegionPermission class defines page definition—specific actions that it maps to the page's operations, as described in Table 30-6.

    Figure 30-10 Granting to an Application Role for an ADF Page Definition in the Overview Editor

    Page definition grant in ADF policy editor
  8. You can repeat these steps to make additional grants as desired.

    The same page definition can have multiple grants made for different application roles. The grants appear in the policy store definition of the jazn-data.xml file, as described in Section 30.5.6, "What Happens When You Define the Security Policy."

30.5.6 What Happens When You Define the Security Policy

When you define a security policy, the jazn-data.xml file overview editor updates the jazn-data.xml file located in the /src/META-INF node relative to the web application workspace.

The overview editor writes the policy information to the <policy-store> section of the file. The security policy, or grant, contains both a grantee and one or more permissions. The grantee is the application role that the policy is being defined for. Each permission defines the resource being secured and the action that can be performed against that resource.

Example 30-7 shows a security policy in the jazn-data.xml file that secures a checkout task flow and secures a top-level web page that lets users update account information. The grant to the fod-users application role contains a view permission for a bounded task flow, checkout-task-flow, and a view permission on the web page with the account_updateUserInfoPageDef page definition. With this grant, only users who are authenticated as members of the fod-users application role will be able to enter the checkout task flow or view the user information update page.

For the web page, notice that permission has been defined on the account_updateUserInfoPageDef page definition created for the user information update page (updateUserInfo.jspx). Also, note that this is a top-level web page that is not already secured by a bounded task flow.

Example 30-7 Grants in the Application-Level Policy Store

<policy-store>
    ...
    <jazn-policy>
        <grant>
            <grantee>
                <principals>
                    <principal>
                        <class>oracle.security.jps.service.policystore.ApplicationRole</class>
                         <name>fod-users</name>
                     </principal>
                 </principals>
             </grantee>
             <permissions>
                  <permission>
                      <class>oracle.adf.controller.security.TaskFlowPermission</class>
                      <name>/WEB-INF/checkout-task-flow.xml#checkout-task-flow</name>
                      <actions>view</actions>
                  </permission>
                   <permission>
                        <class>oracle.security.jps.service.policystore.ApplicationRole</class>
                        <name>oracle.fodemo.storefront.pageDefs.acct_updateUserInfoPageDef</name>
                        <actions>view</actions>
                  </permission>
                  ...
             </permissions>
        </grant>
        ...
    </jazn-policy>
</policy-store>

30.5.7 What Happens at Runtime: How ADF Security Policies Are Enforced

Grants that you make for ADF resources are standard JAAS Permissions. When you enable ADF Security in your application, Oracle Platform Security Service (OPSS) running in Oracle WebLogic Server will utilize the grants to allow authorization. In authorization mode, ADF Security uses fine-grained authorization, implemented with JAAS Permissions to perform security checks for access rights to pages. The ADF Security enforcement logic checks to see whether the user, represented by the JAAS subject, has the right permissions to access the resource.

The subject contains the user's principals, which include a user principal that contains their name (could be anonymous, before logging on, or some user name after logging on), and their list of role principals, which would include authenticated-role and some number of other roles that are obtained from the policy and identity stores. The principal is created to represent all of the user's memberships in application roles defined in the policy store. In turn, each application role may have multiple Permissions associated with them. These are the ADF security policies that are created through the overview editor for the jazn-data.xml file.


Note:

ADF security policies are scoped by application. This scoping allows two applications to refer to the same permission target, without producing unintentional results. You are not required to name application resources to impose application scoping of the policy store information.


Before you run the application using Integrated WebLogic Server, you will need to provision the identity store with test users and add these users to the application roles that you want to configure. The application roles can define members that are specific users or groups of users (also known as enterprise roles), as described in Section 30.6, "Creating Test Users."

Then at runtime, whether the current user has view permission on the page they are trying to access will be determined by the context of the page:

  • If the page is an activity of a bounded task flow, the task flow controller determines the permission.

  • If the page is a top-level page with an associated page definition file, the ADF model determines the permission.

Oracle Platform Security Services then checks to see whether the subject contains the roles that have the corresponding permissions needed to access the page. If the user is authorized, then the task flow is entered.

In the case of a bounded task flow and top-level pages (defined by an unbounded task flow), if the user is not authorized, ADF Controller throws an exception and passes control to an exception handler that the task flow configuration specifies. For details about specifying an error page, see Section 30.7.5, "How to Redirect a User After Authentication."

30.5.8 What You May Need to Know About Defining Policies for Pages with No ADF Bindings

The default Configure ADF Security wizard option ADF Authentication and Authorization enables authorization checking and secures a web page whenever the page is associated with an ADF security-aware resource. Therefore, after you run the wizard, a web page will not be secured if both of these conditions exist:

  • The page does not display databound ADF Faces components and therefore no ADF page definition exists for the page.

  • The page is not a constituent page of a bounded ADF task flow. (Any page that the user accesses as a process of a bounded task flow is checked under the permission of the task flow.)

JDeveloper will generate an ADF page definition file for you whenever you design a web page using the Data Controls panel to create databound ADF Faces components (for details, see Section 12.6, "Working with Page Definition Files"). However, if your web page does not use ADF bindings, you can still create an empty page definition file by right-clicking the web page in the user interface project and choosing Go to Page Definition. The page definition file can remain empty because the page does not need to work with ADF bindings to support databound ADF Faces components.

Once you associate a web page with an ADF page definition file, empty or not, authorization checking will be enforced when the user accesses the associated web page. You can define security policies for the page as you would any other ADF page definition. For details about making grants to an empty ADF page definition, see Section 30.5.5, "How to Define Policies for Web Pages That Reference a Page Definition."

To create an empty page definition that you can define security policies for:

  1. In the Application Navigator, locate the web page you want to secure, right-click and choose Go to Page Definition.

  2. In the confirmation dialog, click Yes to create a new page definition for the page.

    The page definition will be added to the pageDefs package.

30.5.9 How to Use Regular Expressions to Define Policies on Groups of Resources

When you want to define a grant that applies to multiple resources at once, you can create patterns as defined by the java.util.regex.Pattern class to form a regular expression that gets evaluated at runtime. For example, to match a grant to a set of resources, you can enter the expression .* (specifies any character zero or more times) on the name of the permission. ADF Security does not support the use of regular expressions on other security objects, such as the principal name.

You might use this feature to group bounded task flows that would have the same permissions into their own subfolders of WEB-INF and define the grant for the entire folder, as shown in Example 30-8. In this case, the expression uses the dot character (defined as, any character) followed by the asterisk quantifier (defined as, zero or more times).

Example 30-8 Task Flow Permission for an Entire Folder Defined in the Application-Level Policy Store

...
<grant>
   <grantee>
      <principals>
         <principal>
            <class>oracle.security.jps.service.policystore.ApplicationRole</class>
            <name>anonymous-role</name>
         </principal>
      </principals>
   </grantee>
   <permissions>
       <permission>
          <class>oracle.adf.controller.security.TaskFlowPermission</class>
          <name>/WEB-INF/.*</name>
          <actions>view</actions>
       </permission>
   </permissions>
</grant>

As the overview editor for the jazn-data.xml file does not support the use of regular expressions in the user interface, you must edit the file directly. Do not edit the policy store of the system-jazn-data.xml file directly. Instead, add grants using regular expressions to the jazn-data.xml file. These grants will then be merged to the policy store when you run or deploy the application.

The use of more complex regular expressions enables you to define business rules in the policy, thus creating a very targeted set of permissions. For example, you can grant the view permission on all page definitions and deny specific page definitions at the same time by defining an exclusion set in your regular expression. Example 30-9 shows how the view permission is granted to anonymous-role for all pages except those for which the page definition name starts with custom.

Example 30-9 Using Regular Expressions and Metacharacters to Define a Policy Grant

<grant>
   <grantee>
      <principals>
         <principal>
            <class>oracle.security.jps.service.policystore.ApplicationRole</class>
            <name>anonymous-role</name>
         </principal>
      </principals>
   </grantee>
   <permissions>
      <permission>
         <class>oracle.adf.share.security.authorization.RegionPermission</class>
         <name>[^(custom)].*</name>
         <actions>view</actions>
      </permission>
   </permissions>
</grant>

Table 30-7 shows some of the basic regular expression metacharacters that you can use in your policy definitions.

Table 30-7 Description of Metacharacters

MetacharacterDescription

[abc]

a, b, or c (included in list)

[^abc]

Any character except a, b, or c (negation)

[a-zA-Z]

a to z or A to Z, inclusive (range)

[a-d[m-p]]

a to d, or m to p ~= [a-dm-p](union)

[a-z&&[def]]

d, e, or f (intersection)

[a-z&&[^bc]]

a through z, without b and c: [ad-z] (subtraction)

[a-z&&[^m-p]]

a through z, and not m through p

.*

Any number of arbitrary characters (note this expression uses a dot and an asterisk together)


30.5.10 How to Define Policies for Data

ADF entity objects in the model project are security-aware, meaning that predefined resource-specific permissions exist that a developer can grant. Additionally, you can secure just the individual attributes of entity objects.

Entity objects that you secure restrict users from updating data displayed by any web page that renders a UI component bound by an ADF binding to the data accessed by the secured entity object. Additionally, when you secure an entity object, you effectively secure any view object in the data model project that relies on that entity object. As such, entity objects that you secure define an even broader access policy that applies to all UI components bound to this set of view objects. For details about entity-based view objects, see Section 5.2, "Populating View Object Rows from a Single Database Table."

To secure row data using ADF entity objects:

  1. Define a permission map for the specific actions of the entity object or the attributes of the entity object that you want to secure.

  2. Grant the permission to an application role that you have added to the policy store.

30.5.10.1 Defining Permission Maps on ADF Entity Objects

You can secure operations of the entity objects or their individual attributes.

In the data model project, you use the overview editor for the entity object to define a permission map for the specific actions allowed by the entity object. The metadata consists of a permission class, a permission name, and a set of actions mapped to binding operations.

The list of available operations displayed by the overview editor is defined by the entity object permission class (oracle.adf.share.security.authorization.EntityPermission). The permission class maps the operations supported by the entity object to actions. Table 30-8 shows the securable operations of the entity object.

Table 30-8 Securable Operations of ADF Business Components

ADF ComponentSecurable OperationExpected Mapped ActionCorresponding Implementation

ADF Business Components entity objects

read

Read

View the rows of a result set that has been restricted by a WHERE clause fragment.


update

Update

Update any attribute of the bound collection.


removeCurrentRow

Delete

Delete a row from the bound collection.

ADF Business Components attributes of entity objects

update

Update

Update a specific attribute of the bound collection.


To secure all row-level data that the entity object accesses, use the overview editor for the entity object.

Before you begin:

Create entity objects in the model project, as described in Chapter 4, "Creating a Business Domain Layer Using Entity Objects."

To secure an operation on an entity object:

  1. In the data model project displayed in the Application Navigator, double-click the entity object that you want to secure.

  2. In the overview editor, click the General navigation tab.

  3. In the General page, expand the Security section and select the operations you want to secure for the entity object.

    The Security section displays the securable operations that the EntityPermission class defines. The class maps the entity object—specific actions to the entity object's operations, as described in Table 30-8.

    For example, to enable read permission, select it as shown in Figure 30-11. The permissions appear in the XML definition of the entity object.

    Figure 30-11 Permission Enabled on read Operation for an ADF Entity Object

    Read operation enabled for entity object

To secure individual columns of data that the entity object accesses, use the Attributes page of the overview editor for the entity object.

To secure an operation on an entity object attribute:

  1. In the data model project displayed in the Application Navigator, double-click the entity object that defines the attribute you want to secure.

  2. In the overview editor, click the Attributes navigation tab.

  3. In the Attributes page, select the desired attribute, and then expand the Security section and select the operation you want to secure for the entity object attribute.

    The Security section displays the securable operations that the EntityAttributePermission class defines. The class maps the entity object-specific actions to the entity object's operations, as described in Table 30-8.

    For example, to enable update permission, select it as shown in Figure 30-12. The permission map appears in the XML definition of the entity object.

    Figure 30-12 Permission Enabled on update Operation for an ADF Entity Object Attribute

    Update operation enabled on entity object attribute

30.5.10.2 Granting Permissions on ADF Entity Objects

Once a permission target is configured, any data that derives from entity objects or their attributes remains unsecured until you explicitly define policy grants for the entity object's permission target.

To define the access policy for an existing entity object permission target, use the Edit Authorization dialog.

Before you begin:

  1. Run the Configure ADF Security wizard, as described in Section 30.3, "Enabling ADF Security."

  2. Create application roles, as described in Section 30.4, "Creating Application Roles."

  3. Define the permission target for the entity object or the attributes of the entity object, as described in Section 30.5.10.1, "Defining Permission Maps on ADF Entity Objects."

To define the access policy for an entity object:

  1. In the data model project displayed in the Application Navigator, locate the entity object and select it.

  2. In the Structure window for the selected entity object or entity object attribute, right-click and choose Edit Authorization.

    The Edit Authorization dialog displays the available actions of the entity object (or attribute), as described in Table 30-8. The dialog also displays the application roles from the jazn-data.xml policy store. The built-in application roles anonymous-role and authenticated-role will appear with application roles that the application developer created.

  3. In the dialog, select the action that you want to grant to a specific application role.

    For example, to grant Update and Delete privileges to the fod-users application role, select those actions, as shown in Figure 30-13.

    The grant to the application role appears in the jazn-data.xml file.

Figure 30-13 Defining the Access Policy for an Entity Object

Edit Authorization dialog for entity object

30.6 Creating Test Users

JDeveloper provides editors to help you create both the identity and the policy stores. You create both repositories in an application-specific jazn-data.xml file. The editor for the identity store section of the file lets you enter the list of valid user IDs and their assigned passwords. The same editor lets you create application roles and assign the test users or enterprise roles as members of the application roles. Once defined, this information appears in the policy store section of the jazn-data.xml file.

30.6.1 How to Create Test Users in JDeveloper

You seed the identity store of your application with a temporary set of users to simulate the actual users' experience in your production environment. When you run the application in Integrated WebLogic Server, you can log in as any test user and be conferred access rights to view the secure ADF resources of your application.

You can use the identity store to organize users into enterprise roles. Because you typically will configure JDeveloper's deployment options to prevent migrating the identity store to a staging environment, enterprise roles that you create in the jazn-data.xml file are for convenience only. For more details about the use of enterprise roles, see Section 30.4.3, "What You May Need to Know About Enterprise Roles and Application Roles."


Caution:

If you choose to deploy the identity store to your standalone server, you must not create users and enterprise roles in your local identity store that are already configured for Oracle WebLogic Server. For example, if you were to deploy the identity store with the user weblogic and enterprise role Administrators, you would overwrite the default administration configuration on the target server. For a complete list of global roles that Oracle WebLogic Server installs by default, see Oracle Fusion Middleware Securing Resources Using Roles and Policies for Oracle WebLogic Server.


To enable the user to view resources, you make grants against application roles rather than against the users who are the members of those roles. Therefore, after you seed the identity store with test users, you must associate each user or enterprise role group with an application role. This association confers the access rights defined by ADF security policies to users. For details about conferring access rights to users, see Section 30.6.3, "How to Associate Test Users with Application Roles."

To create test users and groups:

  1. From the Application menu, choose Secure > Users.

  2. In the Users page of the jazn-data.xml file overview editor, select the realm for your application from the Realm dropdown menu and perform the following steps.

    JDeveloper automatically creates the default realm jazn.com.

    1. In the Users list, click the New User icon.

    2. In the Name field, enter the user name.

      You should avoid choosing a user name already configured for Oracle WebLogic Server (for example, do not enter webcenter). For the list of user names installed by Oracle WebLogic Server, see Oracle Fusion Middleware Securing Resources Using Roles and Policies for Oracle WebLogic Server.

    3. In the Password field, enter the password for the user and click any other field to add the password to the identity store.

      The password must contain at least eight characters and at least one of the characters must be a special character (such as !, %, ^, &, $ and so on).

  3. Optionally, in the jazn-data.xml file overview editor, click the Enterprise Roles navigation tab, and select the realm for your application from the Realm dropdown menu and perform the following steps.

    You create enterprise roles only when you want to organize users into groups that you will add to an application role. For the purpose of creating test users to run the application using Integrated WebLogic Server, you do not need to create enterprise role groups.

    1. In the Enterprise Roles list, click the New Role icon.

    2. In the Name field, enter the name of the enterprise role and click any other field to add the role to the identity store.

      If you create enterprise role groups, you should avoid choosing a role name that is already configured for Oracle WebLogic Server (for example, do not enter Administrators). For a complete list of the default group names installed by Oracle WebLogic Server, see Oracle Fusion Middleware Securing Resources Using Roles and Policies for Oracle WebLogic Server.

30.6.2 What Happens When You Create Test Users

When you provision the identity store with user identities and enterprise role groups, JDeveloper updates the jazn-data.xml file located in the /src/META-INF node relative to the web application workspace.

The dialog writes the user information to the <jazn-realm> section of the file corresponding to the identity store. Each user identity has a user name and a user login password. Each enterprise role contains one or more member users.

Example 30-10 shows the identity store in the jazn-data.xml file with two users and two enterprise roles. The users ahunold and sking are both members of the fod-users enterprise role, while only sking is a member of the fod-admin enterprise role.

Example 30-10 Users and Enterprise Roles in the Application-Level Identity Store

<jazn-data>
   <jazn-realm default="jazn.com">
      <realm>
         <name>jazn.com</name>
         <users>
            <user>
               <name>sking</name>
               <guid>09FC5C61F68111DCAF1DB790A6B3BAC5</guid>
               <credentials>{903}A0VQ5ozADte7EKIJzcTi6xMZ7YDpRXY5</credentials>
            </user>
            <user>
               <name>ahunold</name>
               <guid>09FEA650F68111DCAF1DB790A6B3BAC5</guid>
               <credentials>{903}/SQSrKZYCLW068VJpHaodILd48mJI47w</credentials>
            </user>
            ...
         </users>
         <roles>
            <role>
               <name>fod-users</name>
               <guid>0A084340F68111DCAF1DB790A6B3BAC5</guid>
               <members>
                  <member>
                     <type>user</type>
                     <name>sking</name>
                  </member>
                  <member>
                     <type>user</type>
                     <name>ahunold</name>
                  </member>
                  ...
               </members>
            </role>
            <role>
               <name>fod-admin</name>
               <guid>0A0CFE30F68111DCAF1DB790A6B3BAC5</guid>
               <members>
                  <member>
                     <type>user</type>
                     <name>sking</name>
                  </member>
                  ...
               </members>
            </role>
            ...
         </roles>
      </realm>
      ...
   </jazn-realm>
</jazn-data>

30.6.3 How to Associate Test Users with Application Roles

Because the ADF Security framework enforces a role-based access control mechanism with permissions granted to application roles, you define a set of roles in the policy store that are specific to your application. For example, in the context of the work flow, there may be roles such as customer, product specialist, supervisor, and administrator.

After you create an application role, you can proceed to associate users that you created in the identity store with one or more roles. At runtime, users who are members of an application role will be conferred the access rights of their application roles. You can assign a user to more than one application role when you want to confer the right of multiple resource grants to a particular user.

For example, one authenticated user might belong to the supervisor role and an employee role, while another user might belong only to the employee role. The security policy for a bounded task flow that permits customer records to be browsed and edited may confer view permission to the supervisor role and limit view permission to the browse page for the employee role. Thus, grants to application roles support multiple levels of access. If the authenticated user is not a member of an application role with a view permission grant for the target ADF resource, the security framework will return an unauthorized user message.

Before you begin:

  1. Run the Configure ADF Security wizard, as described in Section 30.3, "Enabling ADF Security."

  2. Create application roles, as described in Section 30.4, "Creating Application Roles."

  3. Define security policies for ADF security-aware resources, as described in Section 30.5, "Defining ADF Security Policies."

  4. Create test users, and, optionally, create enterprise role groups, as described in Section 30.6.1, "How to Create Test Users in JDeveloper."

To associate users with application roles:

  1. From the Application menu, choose Secure > Application Roles.

  2. In the Application Roles page of the jazn-data.xml file overview editor, select the policy store for your application from the Security Policy dropdown menu.

    The policy store that JDeveloper creates in the jazn-data.xml file are automatically based on the name of your application.

  3. In the Roles list, select an existing application role and complete these tasks as appropriate:

    1. In the Mappings section, click the Add User or Role icon dropdown menu and choose Add User, then in the Select Users dialog select the previously created user from the list and click OK.

    2. Optionally, if you have defined enterprise roles in the identity store, in the Mappings section, click the Add User or Role icon dropdown menu and choose Add Enterprise Role, then in the Select Enterprise Roles dialog select the previously created enterprise role from the list and click OK.

30.6.4 What Happens When You Configure Application Roles

When you associate users with application roles, JDeveloper updates the jazn-data.xml file located in the /src/META-INF node relative to the web application workspace.

The dialog writes the user information to the <policy-store> section of the file. Each application role contains one or more member users or enterprise roles.

Example 30-11 shows the policy store in the jazn-data.xml file with the fod-users application role, which contains two members, sking and ahunold.

Example 30-11 Users Associated with Application Roles in the Application-Level Policy Store

<policy-store>
     <applications>
         <application>
            <name>StoreFrontModule</name>
            <app-roles>
               <app-role>
                  <name>fod-users</name>
                  <display-name>FOD Users</display-name>
                  <class>oracle.security.jps.service.policystore.ApplicationRole</class>
                  <members>
                     <member>
                        <class>oracle.security.jps.internal.core.principals.JpsXmlUserImpl</class>
                        <name>sking</name>
                     </member>
                     <member>
                        <class>oracle.security.jps.internal.core.principals.JpsXmlUserImpl</class>
                        <name>ahunold</name>
                     </member>
                     ...
                  </members>
               </app-role>
               ...
            </app-roles>
            <jazn-policy>
              ...
            </jazn-policy>
         </application>
    </applictions>
</policy-store>

30.7 Creating a Login Page

ADF Security allows for implicit and explicit authentication:

The implicit and explicit authentication scenarios are handled for you by default when you run the Configure ADF Security wizard, as described in Section 30.3.5, "What You May Need to Know About ADF Authentication." However, when you customize the default, generated login page (or supply your own page) to use ADF Faces components, you will need to configure the container-managed deployment descriptor (web.xml file).

To explicitly handle user authentication:


Note:

The following method of handling explicit authentication assumes that you will deploy the Fusion web application to Oracle WebLogic Server. The documented user interface for a JSF-based login page relies on programmatic authentication and uses APIs that are specific to Oracle WebLogic Server and the login process that it supports. This approach relies on programmatic authentication instead of Form-based authentication because it is the most compatible to use with custom login pages.


  1. Create a login link component and add it to the public home web page for your application.

  2. Create a managed bean using API specific to Oracle WebLogic Server to handle the login attempts by the user.

  3. Create a JSF login page using ADF Faces components.

  4. Ensure that the login page's resources are accessible.

For more information about implicit and explicit authentication, see Section 30.8.4, "What Happens at Runtime: How ADF Security Handles Authentication."

30.7.1 How to Create a Login Link Component and Add it to a Public Web Page for Explicit Authentication

You can create a standard login link component that can be added to any page in your application to enable users to authenticate or subsequently log off. This component keeps track of the authenticated state of the user and returns the appropriate login or logout URLs and icons. The login link component will redirect users back to a specific page once they are authenticated. Hence, using this login link component provides you with a single, consistent object.

To the unauthenticated user, the login link component will look similar to Figure 30-14.

Figure 30-14 Component Before User Logs In

Login component icon

Then when the user clicks the login link and logs in as a user with the appropriate credentials, the component will look similar to Figure 30-15.

Figure 30-15 Component After User Logs In

Login component icon

Before you begin:

Copy your login and logout image files (GIF, JPG, or PNG files) to the public_html directory of your project.


Note:

The images used should reference the appropriate skin image if your application uses skins. For more information about skins, see the "Customizing the Appearance Using Styles and Skins" chapter in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.


To create the login link component and add it to a page:

  1. In the Application Navigator, double-click the web page that will display the component.

  2. In the ADF Faces page of the Component Palette, select a Go Image Link component and drag it onto the page.

  3. In the Structure window, right-click af:goImageLink and choose Go to Properties.

  4. In the Property Inspector, set the Text property of the Go Image Link component to render the link text specified by a conditional Expression Language (EL) expression.

    For example, you can enter an EL expression similar to this:

    #{securityContext.authenticated ? &quot;Click to log out&quot; : 
                                      &quot;Click to log in&quot;}
    

    The authenticated property of the securityContext bean will evaluate to true and render the log out option if the current user is authenticated. Otherwise, the link is rendered with the login option.

  5. In the Property Inspector, set the Destination property of the Go Image Link component to forward the user to the URL specified by a conditional EL expression.

    For example, you can enter an EL expression similar to this:

    #{securityContext.authenticated ? &quot;/adfAuthentication?logout=true&amp;
                                        end_url=/faces/welcome&quot; :
                    &quot;/adfAuthentication?success_url=/faces/welcome&quot;}
    

    When the user clicks the link, the URL parameters end_url and success_url forward the destination of the target page to the ADF authentication servlet. Note that the view activity name is passed on the URL parameters instead of the web page name. This ensures control flow rules are enforced for page navigation after login. The authenticated property of the securityContext bean will evaluate to true and forward to the welcome page if the current user is authenticated. When the user is not authenticated, there is no need to forward to the login page because the ADF authentication servlet triggers log in, which is handled by the container-managed security configuration. Note that log out is handled by the ADF authentication servlet which invalidates the session. Although log out is handled by ADF Security, the browser cache must be cleared to complete the process. For a description of a known issue with Basic type authentication and browser caching, see Section 30.7.7, "What You May Need to Know About ADF Servlet Logout and Browser Caching."

  6. In the Property Inspector, to specify the link component image for the Go Image Link component, enter an EL expression in the Icon field.

    For example, this EL expression conditionally renders the link component image as the lock GIF if the user is not authenticated; otherwise, renders the image with the key GIF:

    #{securityContext.authenticated ? "/images/lock.gif" : "/images/key.gif"}
    

    Figure 30-16 shows how the login link component appears when added to the global menu facet of the page.

    Figure 30-16 Login Link Component on the Page

    Login icon on the page

30.7.2 How to Create a Login Page Specifically for Explicit Authentication

The default login form that is generated for you when you run the Configure ADF Security wizard is provided as a convenience for testing your application within JDeveloper. The default form does not allow you to customize the page using ADF Faces components to match the user interface of the application. You can replace the default form with an ADF Faces-based login page that enables you to include customizable components, as shown in Figure 30-17.

Figure 30-17 Login Page

Login page

However, if designing a login page with ADF Faces components is not a requirement, then a simple JSP or HTML login page can be also used. For details about generating a simple login page when running the Configure ADF Security wizard, see Section 30.3.1, "How to Enable ADF Security."

30.7.2.1 Creating Login Code for the Backing Bean

Before you create the login page as an ADF Faces page, you need to create a managed bean to handle login attempts. In this login bean sample, authentication is handled programmatically using Oracle WebLogic Server-specific API for Basic authentication. Consequently, there is no need to invoke the ADF authentication servlet to redirect to a landing page upon login; the bean doLogin() method handles this task programmatically. You will add this bean to the adfc-config.xml file and register it with request scope.

Note that the Oracle WebLogic Server API used in this backing bean sample can also be used when you want to perform authentication from the user's current page (for example, from a home page) and do not want the application to navigate off the current page to display a login page.


Note:

Note that the backing bean you will create in this procedure relies on APIs that are specific to Oracle WebLogic Server and the login process that it supports. Only use this procedure when you will deploy the Fusion web application to Oracle WebLogic Server.


Before you begin:

It may be helpful to have an understanding of the login page. For more information, see Section 30.7.2, "How to Create a Login Page Specifically for Explicit Authentication."

You will need to complete this task:

  • In the user interface project where you create the backing bean for login, import the following library into your project:

    • WebLogic 10.3 Remote-Client

    To import the library, double-click the user interface project node in the Applications window. In the Project Properties dialog, select Libraries and Classpath and then click Add Library. In the Add Library dialog, expand the Extensions node and scroll to locate the WebLogic 10.3 Remote-Client library to add. This library will allow the user interface project to compile and resolve the following import statements from the backing bean code sample.

    import weblogic.security.URLCallbackHandler;
    import weblogic.servlet.security.ServletAuthentication;
    

    For details about creating a library and adding it to a project, refer to the JDeveloper online help.

To create and register a backing bean for login:

  1. In the Application Navigator, under the user interface project, right-click your application and choose New.

  2. In the New Gallery, expand General, select Java and then Java Class, and click OK.

  3. In the Create Java Class dialog, enter the name for the login page backing bean class file and disable the default options Constructors from Superclass and Implement Abstract Methods, and click OK.

    For convenience, you might name the backing bean based on the name of your login page, for example, LoginPageName.java.

  4. In the Applications Navigator, expand the Application Sources node and double-click the new LoginPageName.java backing bean.

  5. In the source editor, create two private fields by adding the following in the declaration section of the LoginPageName.java file:

    private String _username;
    private String _password;
    
  6. Generate or create public accessors for both fields.

    You can right-click in the source editor and choose Generate Accessors to add the following public accessors to the file:

    public void setUsername(String _username) {
        this._username = _username;
    }
    
    public String getUsername() {
        return _username;
    }
    
    public void setPassword(String _password) {
        this._password = _password;
    }
    
    public String getPassword() {
        return _password;
    }
    
  7. Add a doLogin() method to this Java class to handle user attempts to log in:

    1 public String doLogin() {
    2   String un = _username;
    3   byte[] pw = _password.getBytes();
    4   FacesContext ctx = FacesContext.getCurrentInstance();
    5   HttpServletRequest request =
    6                  (HttpServletRequest)ctx.getExternalContext().getRequest();
    7   try {
    8       CallbackHandler handler = new URLCallbackHandler(un, pw);
    9       Subject mySubj = 
    10                 weblogic.security.services.Authentication.login(handler);
    11      weblogic.servlet.security.ServletAuthentication.runAs(mySubj, request);
    12      ServletAuthentication.generateNewSessionID(request);
    13      String loginURL = "faces/mylandingpage.jspx";
    14      sendForward(loginURL);
    15   } catch (FailedLoginException fle) {
    16      FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR,
    17                                        "Incorrect Username or Password",
    18                                        "An incorrect Username or Password" +
    19                                        " was specified");
    20      ctx.addMessage(null, msg);
    21      setPassword(null);
    22   } catch (LoginException le) {
    23      reportUnexpectedLoginError("LoginException", le);
    24   }
    25   return null;
    26 }
    

    The doLogin() method performs the following tasks:

    Lines 4-6 get an object encapsulating the HTTP request from the FacesContext.

    Line 8 creates a CallbackHandler, which is an object that retrieves information for security operations. A URLCallbackHandler allows security operations to retrieve the username and password that were passed to its constructor; other CallbackHandler implementations can obtain the username and password from another source.

    Line 9-10 creates a Subject, which is an object that encapsulates credentials, from the information provided by the CallbackHandler.

    Line 11 attempts to log in the user issuing the request using the credentials encapsulated by the Subject.

    Line 12 ensures that the session ID for the session is changed after the user is successfully authenticated. This is necessary to prevent leaving the application open to a session fixation attack, which would be a security vulnerability.

    Lines 13 constructs a URL to which to forward the user after successful login. Note that in this login bean sample, authentication is being handled entirely by Oracle WebLogic Server. Because the sample is platform-specific, there is no need to invoke the ADF authentication servlet to redirect after login. Enabling the ADF Security authentication servlet is useful when you need to implement platform-independent, Java EE container-managed login and wish to implement implicit authentication.

    Line 14 calls a method, sendForward(), which you will implement later in this section to forward the user to the URL specified in Line 13.

    Lines 15-21 handle a FailedLoginException, which is the exception thrown when the credentials supplied are incorrect. The lines handle the exception by adding a new message to the FacesContext.

    Lines 22-23 handle a LoginException, which can be thrown by many different problems with a login. For example, exceptions can result from incorrect credentials or attempts to log into a locked account or uses of an expired password. FailedLoginException is a subclass of LoginException, but since a FailedLoginException will be caught by Line 17, these lines will only be executed when there are login problems other than incorrect credentials. reportUnexpectedLoginError() is a method which you will implement to deal with miscellaneous problems with the login process.

    Line 25 returns null so that ADF Controller will not attempt to follow a control flow case.

  8. Import the following classes:

    javax.faces.application.FacesMessage
    javax.faces.context.FacesContext
    javax.security.auth.Subject
    javax.security.auth.callback.CallbackHandler
    javax.security.auth.login.FailedLoginException
    javax.security.auth.login.LoginException
    javax.servlet.http.HttpServletRequest
    weblogic.security.URLCallbackHandler
    weblogic.servlet.security.ServletAuthentication
    
  9. Create stubs for the methods sendForward() and reportUnexpectedLoginError().

  10. Add a sendForward() method with its actions:

    1  private void sendForward(String forwardUrl) {
    2    FacesContext ctx = FacesContext.getCurrentInstance();
    3    try {
    4      ctx.getExternalContext().redirect(forwardUrl);
    5    } catch (IOException ie) {
    6      reportUnexpectedLoginError("IOException", ie);
    7    }
    8     ctx.responseComplete();
    9  }
    

    The sendForward() method performs the following tasks:

    Line 2 gets the ADF Faces ctx, which forwards a response to a particular URI.

    Lines 3-4 uses the ctx to redirect the current HTTP response to the URL.

    Lines 5-6 handle an IOException, which is thrown when the request cannot be read or the response cannot be written to.

    Line 8 marks the HTTP response as complete so that the browser can finish rendering it.

  11. Import the following classes:

    javax.servlet.RequestDispatcher
    javax.servlet.ServletException
    java.io.IOException
    
  12. Implement a reportUnexpectedLoginError() method:

    private void reportUnexpectedLoginError(String errType, Exception e){
      FacesMessage msg =
        new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unexpected error 
                                                              during login",
                         "Unexpected error during login (" + errType + "),
                            please consult logs for detail");
      FacesContext.getCurrentInstance().addMessage(null, msg);
      FacesContext.getCurrentInstance().renderResponse();
    }
    

    This reportUnexpectedLoginError() method adds a summary error message to the FacesContext, and then prints the full stack trace of the exception to the console.

  13. Save the Java file.

  14. In the Application Navigator, double-click the adfc-config.xml file in the WEB-INF folder.

  15. In the editor window for the adfc-config.xml file, click the Overview tab.

  16. In the overview editor for task flows, click the Managed Beans navigation tab.

  17. In the Managed Beans page, in the Managed Beans section click the Add icon and enter a name for the bean, enter the fully qualified class name, and select request scope.

    For example, the class name might look like oracle.foddemo.security.Login, as shown in Figure 30-18.

    Figure 30-18 Login Bean Registered in adfc-config.xml File

    Configuration editor shows login bean
  18. Save all.

30.7.2.2 Creating an ADF Faces-Based Login Page Specifically for Explicit Authentication

A simple login page that utilizes ADF Faces layout components and ADF Faces user interface components includes two input fields and a button. You must bind the properties of these UI components to the login handler methods that you defined in the managed bean for the login page.

Note that the page that you can create with this procedure does not support implicit authentication. When you choose to implement implicit authentication, you can customize the default, wizard-generated login form which supports container-managed authentication. The Java EE container expects a form that relies on the j_security_check mechanism to handle user-submitted j_username, and j_password input. In the explicit authentication scenario documented here, Java EE container-managed authentication is not used.

Before you begin:

Create the managed bean to handle the user's login attempts, as described in Section 30.7.2.1, "Creating Login Code for the Backing Bean."

To create the ADF Faces-based login page for explicit authentication:

  1. In the Application Navigator, under the user interface project, right-click your application and choose New.

  2. In the New Gallery, expand Web Tier, select JSF and then JSF Page, and click OK.

  3. In the Create JSF Page dialog, select Create as XML Document (*.jspx).

  4. In the File Name field, specify a name for your login page. For example, enter LoginPage.jspx.

    Select no other options and do not select the option to expose UI components in a managed bean. You will manually bind the components to the managed bean you created for the login page.

  5. Click OK.

  6. Save the page.

  7. In the ADF Faces page of the Component Palette, from the Layout panel, select the Panel Box component and drag it onto the Structure window below the af:form tag.

  8. In the Property Inspector, set the Text, Horizontal, Width, and Height properties.

    For example, to recreate the login page shown in the Master Price List module of the Fusion Order Demo application, you would enter:

    Text set to Login Information

    Icon set to /images/key_ena.png

    Width/Height set to 300/200 pixels

  9. From the Component Palette, drag a Panel Form Layout component below the af:panelBox tag in the Structure window, as shown in Figure 30-19.

    Figure 30-19 Login Page Structure with Panel Form Layout

    Structure of login page with panel form layout
  10. From the Component Palette, in the ADF Faces page, drag an Input Text component onto the Panel Form Layout component for the username field and another Input Text component for the password field.

  11. In the Property Inspector, set the input fields' Label property to Username and Password and set both fields' Behavior - Required property to true.

  12. In the Property Inspector, set the password field's Appearance - Secret property to true.

  13. To handle processing of the values for the two input fields, perform these steps for each field:

    1. In the Structure window, select one of the input fields (for example, select the af:inputText - Username tag), then click the Property Menu icon to the right of the Value property in the Property Inspector and choose Expression Builder.

    2. In the Expression Builder, expand ADF Managed Beans and expand your login bean, then select the expression value corresponding to your bean's handler method.

      For example, if you selected the username input field in the Structure window, then you would select username from the Expression Builder dialog, as shown in Figure 30-20.

      Figure 30-20 username Selection in Expression Builder Dialog

      Expression Builder shows login bean method selection
    3. Click OK.

      The expression shown in the Property Inspector binds the field to the managed bean you created for the login page. For example, for the username input field, the expression is similar to #{loginPageBean.username} as shown in Figure 30-21.

      Figure 30-21 username Value in Property Inspector

      Property Inspector shows username value
  14. From the Component Palette, drag a Panel Border Layout component inside the footer folder of the af:panelBox tag, as shown in Figure 30-22.

    Figure 30-22 Login Page Structure with Panel Border Layout

    Structure of login page with panel border layout
  15. In the JSP/HTML visual editor, delete the panel border layout facets labeled End, Top, and Bottom. Leave only the Start facet.

  16. In the Structure window, expand the Panel Border Layout facets folder and select the start folder, and then select the Button component in the Component Palette.

  17. In the Property Inspector, set the button component's Text property to Login.

  18. To handle processing of the login button action, perform these steps.

    1. In the Structure window, select the login af:commandButton tag in the start folder, then click the Property Menu icon to the right of the Action property in the Property Inspector and choose Expression Builder.

    2. In the Expression Builder, expand ADF Managed Beans and expand your login bean, then select the expression value corresponding to your login method.

      For example, if you created a method in the login bean named doLogin(), then you would select doLogin in the Expression Builder dialog.

    3. Click OK.

      The expression shown in the Property Inspector binds the button to the managed bean you created for the login page. For example, for the login button, the expression is similar to #{loginPageBean.doLogin} as shown in Figure 30-23.

      Figure 30-23 login Action in Property Inspector

      Property Inspector shows login action
  19. Save the page.

30.7.2.3 Ensuring That the Login Page Is Public

Because the application is secured by ADF Security, all web pages defined within bounded task flows and any web page defined by an ADF page definition will be inaccessible by default. Since all users must be allowed to log on, the login page should remain publicly accessible, and thus you should add no databound components to the page. As long as the login page uses no databound components, then it will be accessible by default.

No further steps are required to ensure that the container will always redirect to the defined authentication point before allowing access to the page (which in this case is the authentication page).

30.7.3 How to Ensure That the Custom Login Page's Resources Are Accessible for Explicit Authentication

When you run the ADF Security wizard and choose the ADF Authentication option (because you do not want to enable ADF authorization) and your application uses a custom login page or a custom error page, you may need to edit the default Java EE security constraint added to the web.xml file by ADF Security. As shown in Figure 30-12, the default URL pattern (/*) defined in the allPages security constraint covers everything under the Java EE application root, meaning that the resource files (such as images, style sheets, or JavaScript library) used by the login page are also included.

Example 30-12 Java EE Security Constraint for ADF Authentication Only

<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>

If the pages you create use resources, such as images, CSS files, or JavaScript libraries, the default allPages security constraint in the web.xml file will prevent those resources from loading at runtime. To allow your application to display those resources, you should save the resources in a folder of their own and then edit the allPages security constraint so that the resources folder is not contained in the URL pattern.

Note that this resource issue does not apply when you run the ADF Security wizard and choose the ADF Authentication and Authorization option (the default). Specifically, in that case, the default generated constraint is on the ADF Authentication servlet and the constraint (/adfAuthentication) excludes any resource files.

30.7.4 How to Create a Public Welcome Page

Because web applications are generally secured, there is always a need for a starting point or home page for unauthenticated users. To create this public welcome page, you create an ADF Faces page to act as the entry point for the application, which contains links to other pages within the application. However, only links to public pages should be rendered to unauthenticated users and, conversely, links to secured pages should be rendered only after the user has logged in and has the appropriate privileges to view the target page.


Best Practice:

When the user presses Ctrl-N or Ctrl-T to open a new browser window or tab and no welcome page is defined in the application's web.xml file, the browser will display a 403 or 404 error. To prevent this error, you must specify a welcome page definition in the application's web.xml file. You can create this definition when you run the Configure ADF Security wizard. For details about running the wizard, see Section 30.3.1, "How to Enable ADF Security."


30.7.4.1 Ensuring That the Welcome Page Is Public

After you have created a regular ADF Faces page, the page will, by default, be public and accessible by unauthenticated users. If, however, you have associated the welcome page with an ADF resource, for example, by dropping databound ADF Faces components into the welcome page using the Data Controls panel, then ADF Security will secure the page by default. You can make any ADF resource publicly accessible using the jazn-data.xml file overview editor to grant a view privilege on the resource to the provided anonymous-role. For details about the anonymous-role see, Section 30.5.2, "What Happens When You Make an ADF Resource Public."

30.7.4.2 Adding Login and Logout Links

You can add login and logout links to your public welcome page so that users can explicitly log in and out while they are in the application. While Java EE container-managed security supports the concept of authentication when accessing a secured resource, there is no standard way to log out and stay within a secured application. However, it is a common practice in web applications to allow the user to stay on the same page if that page is public or to return the user to the welcome page if that page is secured. While adding the login and logout links to each page would let the user end their login session anywhere within the application (and return to the welcome page), having these links on the welcome page enables users to explicitly authenticate on entering the application.

For example, you can create an ADF Faces panel group with three components, including an output text area, an image, and a go link. To render the appropriate login or logout link, you can use an EL expression that evaluates the user's authentication status. Specifically, you can use securityContext.authenticated to access the ADF security context, as shown in Example 30-13. The expression evaluates to true or false and, in this example, the result determines which login/logout image and link to display. As Example 30-13 shows, the success_url and end_url parameters for the ADF authentication servlet are passed as the view activity welcome associated with the target page welcome.jspx. Passing the view activity name instead of the web page name for the URL parameters ensures the Fusion web application uses task flow control flow rules to handle page navigation.

Example 30-13 ADF Faces Components and EL Expressions to Render Login/Logout Link

<af:panelGroupLayout inlineStyle="width:100%; height:15px;" id="ptpgl3">
     <af:spacer width="7" height="10" id="pts2"/>
     <af:outputText value="Welcome #{securityContext.userName}!"
                           inlineStyle="font-weight:bold; width:100px" id="ptot2"
                           rendered="#{securityContext.authenticated}"/>
     <af:image source="#{securityContext.authenticated ? '/images/lock.gif' : '/images/key.gif'}"
               id="pti2" inlineStyle="width:16px; height:16px;" shortDesc="switchable icon"/>
     <af:goLink text="#{securityContext.authenticated ? &quot;Logout&quot; : &quot;Login&quot;}"
                destination="#{securityContext.authenticated ? 
                       &quot;/adfAuthentication?logout=true&amp;end_url=/faces/welcome&quot; : 
                            &quot;/adfAuthentication?success_url=/faces/welcome&quot;}"
                inlineStyle="color:Blue; font-size:14px; font-weight:bold;"/>
      <f:facet name="separator">
         <af:spacer width="5" height="10" id="pts1"/>
      </f:facet>
</af:panelGroupLayout>

As an alternative to rendering the link directly within a page, you can create a login link component with the login and logout links that you can add to a page template, as described in Section 30.7.1, "How to Create a Login Link Component and Add it to a Public Web Page for Explicit Authentication."

30.7.4.3 Hiding Links to Secured Pages

Since an anonymous user should not have access to any secured pages, any navigation component on the welcome page that points to a secured page should be hidden from view based on the following two criteria:

  • Is the user authenticated with a known user identity?

  • Does the specified user identity have permission to view the target?

If either of these criteria has not been met, the rendered attribute of any navigation component on a public page that points to a secured resource must have its rendered property set to false, thus hiding it from the anonymous user. To enforce these rules within your welcome page, see Section 30.11.1, "Using Expression Language (EL) with ADF Security."

30.7.5 How to Redirect a User After Authentication

When you have chosen to implement implicit authentication, after the user accesses a secured web page and logs in, the ADF authentication servlet will redirect back to the original page that initiated the login request. With ADF Security authentication enabled, the ADF authentication servlet automatically passes the original page as the ADF authentication success_url parameter on the URL. Typically, this is the desired behavior. However, when you display an explicit login link in your page, the destination of the target will typically be a secured page. You ensure the ADF Authentication servlet redirects to the secured page after authentication by passing the view activity name of the web page as the servlet success_url parameter, as shown in Example 30-14.

Example 30-14 Explicit Login Link with success_url in a Web Page

<af:goLink text="Login" destination="/adfAuthentication?success_url=/faces/viewactivityname"/>

Additionally, you can specify the success_url parameter as an <init-param> within the web.xml file to handle any cases where it is not possible to redirect to the original page. Thus, when the user accesses the secured web page and gets redirected to log in, the framework automatically passes the original page as the success_url parameter on the URL, which supersedes any web.xml setting. Therefore, in practice the only scenario in which an <init-param> setting in web.xml takes effect is when the user explicitly types the adfAuthentication URL into the browser.

In cases where the user is authenticated but not authorized to view a web page, you can redirect the ADF authentication servlet to an error page in your application. Error handling in Fusion web applications is under the control of the ADF Controller exception handler unless you have created an application that does not use a task flow in its design. For example, in an unbounded task flow, where you have defined an unbounded task flow with a top-level welcome page and a browse page (secured through its ADF page definition), you would see an error page from the application, named authorizationErrorPage.jspx, specified in the adfc-config.xml file, as shown in Example 30-15.

Example 30-15 Error Page Redirect for Applications That Use Task Flows

<adfc-config xmlns="http://xmlns.oracle.com/adf/controller" version="1.2">
  <exception-handler>authorizationErrorPage</exception-handler>
  <view id="welcomePage">
    <page>/welcomePage.jspx</page>
  </view>
  <view id="browse">
    <page>/browse.jspx</page>
  </view>
  <view id="authorizationErrorPage">
    <page>/authorizationErrorPage.jspx</page>
  </view>
  <control-flow-rule>
    <from-activity-id>welcomePage</from-activity-id>
    <control-flow-case>
      <from-outcome>goToSecuredPage</from-outcome>
      <to-activity-id>browse</to-activity-id>
    </control-flow-case>
  </control-flow-rule>
</adfc-config>

For details about how to specify an error page as a view activity for the ADF Controller exception handler, see Section 18.7, "Handling Exceptions in Task Flows."

In cases where the user is not authenticated and an authorization failure occurs, the framework redirects to the ADF authentication servlet, which in turn triggers a Java EE constraint that prompts for login. In this case, container-managed security relies on the login page and error page that you specify in the <login-config> element of the web.xml file.

If you create a Fusion web application without utilizing task flows, then you can specify an <init-param> setting in web.xml for the ADF binding filter, as shown in Example 30-16. In this case, when no task flow is present in the application, page authorization checking is handled by the ADF binding filter, and the unauthorizedErrorPage parameter will be passed to the ADF binding request handler.


Note:

The unauthorizedErrorPage parameter feature is provided for compatibility with previous releases where ADF Controller was not available. In Fusion web applications, when you need to redirect users to an error page, you use the task flow exception handler to specify the error page, as shown in Example 30-15.


Example 30-16 Error Page Redirect for Applications That Don't Use Task Flows

<filter>
    <filter-name>adfBindings</filter-name>
    <filter-class>oracle.adf.model.servlet.ADFBindingFilter</filter-class>
    <init-param>
        <param-name>unauthorizedErrorPage</param-name>
        <param-value>faces/authorizationErrorPage.jspx</param-value>
    </init-param>
</filter>

30.7.6 How to Trigger a Custom Login Page Specifically for Implicit Authentication

When you have chosen to implement implicit authentication to allow users to access protected resources (which may be by direct URL access or by navigating to an ADF Security protected resource), the ADF Security authentication servlet initiates the Java EE container to display the login form configured in the web.xml file. For implicit authentication, when you have customized the default, wizard-generated login form to use ADF Faces components, you must modify the URL pattern for the servlet mapping to reference the ADF Faces servlet.

You can accomplish this in the Authentication Type page of the Configure ADF Security wizard when you configure ADF Security, or in the web.xml file directly. If you have already run the Configure ADF Security wizard, you can use the following procedure to confirm that the web.xml file has been updated as described.

When you have choose to implement explicit authentication and have created a public page to allow users to login to access protected resources, the login form you create will not be triggered by ADF Security. In the explicit authentication scenario, you do need to configure the web.xml file.


Caution:

Configuring the web.xml file when your application implements explicit authentication programmatically and you have created a login page, as described in Section 30.7.2.2, "Creating an ADF Faces-Based Login Page Specifically for Explicit Authentication" may produce unpredictable results and login may fail. Only modify the web.xml file when you are implementing implicit authentication and you have created a form that relies on the j_security_check action, as does the default, wizard-generated login form.


To reference an ADF Faces login page for implicit authentication:

  1. In the Application Navigator, expand the WEB-INF node and double-click web.xml.

  2. In the overview editor, click the Security navigation tab.

  3. In the Security page, expand the Login Authentication section, and set the login page to include a reference to the ADF Faces servlet such that the login page can be part of the ADF Faces lifecycle /faces/ADFlogin.jspx page.

    When you add a page using the file browser, the path entered in the web.xml file will not specify /faces. Modify the entry so that the path references the servlet mapping path for the ADF Faces servlet. For example, if the URL pattern specified by the mapping is /faces/*, then your path should look like /faces/yourpage.jspx, as shown in Figure 30-24.

    Figure 30-24 Adding a Reference to the Faces Servlet in the Login Configuration

    Form-based authentication for ADF Faces servlet

30.7.7 What You May Need to Know About ADF Servlet Logout and Browser Caching

When basic type authentication is in effect as specified in the application's web.xml file, the browser caches authentication credentials. This is a known issue with basic authentication that prevents the ADF authentication servlet from completing log out and allows users to access resources after logout. In this scenario, in order to complete the logout session, it is necessary to close the browser and restart a new browser session.To ensure the ADF authentication servlet completes logout and prevents a user from being able to access resources after logout, use form-based authentication instead of basic authentication. You can select form-based authentication when you run the Configure ADF Security wizard, as described in Section 30.3.1, "How to Enable ADF Security."

30.7.8 What You May Need to Know About IBM WebSphere Application Server

When you deploy your application to IBM WebSphere application servers and use the same machine to log into the WebSphere administrative console, your application may display the name of the user logged into the administrative console, instead of the name of the user who logs into the application. Normally, an expression that tests for the authenticated user like #{securityContext.authenticated ? securityContext.userName : ""} should display the name of the user who logs into the application. However, the administration user's name is displayed on IBM WebSphere application servers when the application is running in Mozilla Firefox, where the session ID is shared across all browsers on the same machine. This behavior is not observed when running on Oracle WebLogic Server or when running the application in Microsoft Internet Explorer.

30.8 Testing Security in JDeveloper

Integrated WebLogic Server enables you to run the application directly within JDeveloper and determine whether or not to migrate security objects, including the application policies, users, and credentials that your application defines. By default, all security objects are migrated to Integrated WebLogic Server each time you run the application.

30.8.1 How to Configure, Deploy, and Run a Secure Application in JDeveloper

JDeveloper is configured by default to deploy the security objects from your application repositories to Integrated WebLogic Server each time you run the application. You can change this behavior by selecting security deployment options in the Application Properties dialog to:

  • Decide whether to overwrite the domain-level policies with those from the application jazn-data.xml file

  • Decide whether to overwrite the system credentials from the application's cwallet.sso file

    The cwallet.sso file (located in JDeveloper in the Application Resources panel of the Applications window under the Descriptors-META-INF node) stores credentials as securely kept objects that are presented to the authentication provider to be matched against identities. The file is encrypted and cannot be browsed or edited within JDeveloper. At design-time, different components make use of cwallet.sso file and are responsible for creating the necessary credentials in it.

  • Decide whether to migrate the identity store portion of the jazn-data.xml file to the domain-level identity store

If you make no changes to the deployment settings, each time you run the application, JDeveloper will overwrite the domain-level security policies and system credentials. Additionally, JDeveloper will migrate new user identities you create for test purposes and update existing user passwords in the embedded LDAP server that Integrated WebLogic Server uses for its identity store. However, if you prefer to run the application without updating the existing security objects in Integrated WebLogic Server, you have this option.

To configure security deployment and run the application in JDeveloper:

  1. From the Application menu, choose Secure > Configure Security Deployment.

  2. In the Application Properties dialog, in the Deployment page, in the Security Deployment Options section, select the security objects that you want to deploy to Integrated WebLogic Server.

    By default, each time you run the application, JDeveloper will overwrite the application policies and system credentials at the domain level with those from the application. If you prefer not to overwrite either of these repositories, deselect Application Policies or Credentials. When deselected, JDeveloper will merge only new polices or credentials into the domain-level stores.

    By default, each time you run the application, JDeveloper will migrate new user identities you create for test purposes and update existing user passwords in the embedded LDAP server that Integrated WebLogic Server uses for its identity store. You can disable migration of the application identity store by deselecting Users and Groups.

  3. Click OK.

  4. In the Application Navigator, right-click the UI project that contains the secured web pages and choose Run.

    When you choose Run on the UI project, JDeveloper will run the application using the default run target you configured for the project. For example, you can configure a task flow activity as the run target to start your application. To configure the default run target, see Section 14.4, "Testing ADF Task Flows."

    The Configure Default Domain dialog displays the first time you run the application and start a new domain in Integrated WebLogic Server. Use the dialog to define an administrator password for the new domain. Passwords you enter can be eight characters or more and must have a numeric character.

30.8.2 What Happens When You Configure Security Deployment Options

When you run the application using Integrated WebLogic Server, JDeveloper migrates the security policies and credentials to the domain level based on security deployment configuration settings specified in the Application Properties dialog. During the deployment process, JDeveloper updates the weblogic-application.xml file that it adds to the deployment archive file with the Application Properties settings, as shown in Example 30-17. Note that these settings are not added to the weblogic-application.xml file in the application source directory and thus are not visible.

Example 30-17 Default Security Deployment Settings in the Archive weblogic-application.xml File

<application-param>
    <param-name>jps.credstore.migration</param-name>
    <param-value>OVERWRITE</param-value>
</application-param>
<application-param>
    <param-name>jps.policystore.migration</param-name>
    <param-value>OVERWRITE</param-value>
</application-param>

The OVERWRITE value allows you to modify the security policies and credentials in your application and redeploy either to Oracle WebLogic Server running in development mode or to Integrated WebLogic Server (set up to run in development mode by default).


Note:

When you eventually deploy to a production environment, the migration settings in the weblogic-application.xml file are ignored; it would be considered a security vulnerability to allow existing policies and credentials to be overwritten. For information about deploying to a production environment, see Section 30.9, "Preparing the Secure Application for Deployment."


JDeveloper also updates the weblogic-application.xml file with OPSS lifecycle listeners, as shown in Example 30-18. To initiate the migration process before the application runs, the lifecycle listeners observe the migration settings for policies and credentials and overwrite the security objects at the domain level.

Example 30-18 Security Migration Listeners in the Archive weblogic-application.xml File

<listener>
    <listener-class>
        oracle.security.jps.wls.listeners.JpsApplicationLifecycleListener
    </listener-class>
</listener>
<listener>
    <listener-class>
        oracle.security.jps.wls.listeners.JpsAppVersionLifecycleListener
    </listener-class>
</listener>

During the migration process, JDeveloper maps the Oracle Platform Security Services (OPSS) application role member classes to the Integrated WebLogic Server member classes and migrates the users to WebLogic Server identity store users and migrates the roles to Integrated WebLogic Server identity store groups. In Oracle WebLogic Server, users is an implicit group equivalent to OPSS authenticated-role.

Example 30-19 Application Role Fragment in the system-jazn-data.xml File

<app-roles>
   <app-role>
      <name>fod-users</name>
      <guid>FFFF394F696E786F4134485764511002</guid>
      <display-name/>
      <description/>
      <class>oracle.security.jps.service.policystore.ApplicationRole</class>
      <members>
         <member>
            <name>fod-users</name>
            <class>weblogic.security.principal.WLSGroupImpl</class>
         </member>
      </members>
   </app-role>
</app-roles>

Identity store migration is not controlled by the application lifecycle listener settings in the weblogic-application.xml file. Instead, an Oracle WebLogic Mbean handles migrating the identities when running in Integrated WebLogic Server or when deploying from JDeveloper. If the user already exists, the Mbean will not migrate the entire user definition. Only the user password will be updated.

30.8.3 How to Use the Built-In test-all Application Role

When you run the Configure ADF Security wizard, you can enable the option to add the test-all application role to the policy store in the jazn-data.xml file. When you enable this option, you also specify the scope of grants to the application role for your application:

  • Select Grant to Existing Objects Only when you want JDeveloper to grant view rights to the test-all application role and you want this policy to apply to all the ADF task flows and web pages that appear in your user interface project at the time you run the wizard.

  • Select Grant to All Objects when you want JDeveloper to grant view rights to the test-all application role and you want this policy to apply to all existing and future ADF task flows and web pages that developers will create in the user interface project. Note that the wizard displays the option Grant to New Objects after you run the wizard the first time with the Grant to All Objects option selected.

After you run the wizard, the test-all role appears in the jazn-data.xml file and is visible in the jazn-data.xml file overview editor. You will not need to populate the test-all role with test users since the wizard assigns the built-in application role anonymous-role to the test-all role. In this case, all users will automatically have the anonymous-role principal and will be permitted to access the application.


Note:

Before you deploy the application, you must remove all occurrences of the test-all role from the policy store, as described in Section 30.9.1, "How to Remove the test-all Role from the Application Policy Store." This will prevent unauthorized users from accessing the web pages of your application.


You can rerun the wizard and disable automatic grants at any time. Once disabled, new ADF task flows and web pages that you create will not utilize the test-all role and will therefore require that you define explicit grants, as described in Section 30.5, "Defining ADF Security Policies."

30.8.4 What Happens at Runtime: How ADF Security Handles Authentication

When you test the application in JDeveloper using Integrated WebLogic Server, the identity store is migrated to the embedded LDAP server, with information stored in Oracle Internet Directory.

Figure 30-25 illustrates the authentication process when users attempt to access an ADF bounded task flow or any web page containing ADF bindings (such as mypage.jspx) without first logging in. Authentication is initiated implicitly because the user does not begin login by clicking a login link on a public page. In the case of the secured page, no grants have been made to the anonymous user.

Figure 30-25 ADF Security Implicit Authentication

ADF security implicit authentication process

In Figure 30-25, the implicit authentication process assumes that the resource does not have a grant to anonymous-role, that the user is not already authenticated, and that the authentication method is Form-based authentication. In this case, the process is as follows:

  1. When the bounded task flow or web page (with ADF bindings) is requested, the ADF bindings servlet filter redirects the request to the ADF authentication servlet (in the figure, Step 1), storing the logical operation that triggered the login.

  2. The ADF authentication servlet has a Java EE security constraint set on it, which results in the Java EE container invoking the configured login mechanism (in the figure, Step 2). Based on the container's login configuration, the user is prompted to authenticate:

    1. The appropriate login form is displayed for form-based authentication (in the figure, Step 2a).

    2. The user enters their credentials in the displayed login form (in the figure, Step 2b).

    3. The user posts the form back to the container's j_security_check() method (in the figure, Step 2c).

    4. The Java EE container authenticates the user, using the configured pluggable authentication module (in the figure, Step 2d).

  3. Upon successful authentication, the container redirects the user back to the servlet that initiated the authentication challenge, in this case, the ADF authentication servlet (in the figure, Step 3).

  4. On returning to the ADF authentication servlet, the servlet subsequently redirects to the originally requested resource (in the figure, Step 4).

    Whether or not the resource is displayed will depend on the user's access rights and on whether authorization for ADF Security is enforced, as explained in Section 30.8.5, "What Happens at Runtime: How ADF Security Handles Authorization."

Figure 30-26 illustrates the explicit authentication process when the user becomes authenticated starting with the login link on a public page.

Figure 30-26 ADF Security Explicit Authentication

ADF security explicit authentication process

In an explicit authentication scenario, an unauthenticated user (with only the anonymous user principal and anonymous-role principal) clicks the Login link on a public page (in the figure, Step 1). The login link is a direct request to the ADF authentication servlet, which is secured through a Java EE security constraint in the web.xml file.

In this scenario, the current page is passed as a parameter to the ADF authentication servlet. As with the implicit case, the security constraint redirects the user to the login page (in the figure, Step 2). After the container authenticates the user, as described in Step a through Step d in the implicit authentication case, the request is returned to the ADF authentication servlet (in the figure, Step 3), which subsequently returns the user to the public page, but now with new user and role principals in place.

30.8.5 What Happens at Runtime: How ADF Security Handles Authorization

When ADF authorization is enabled, the ADF bounded task flows and web pages outside of a task flow that have an ADF page definition will be secure by default. When a user attempts to access these web pages, ADF Security checks to determine whether the user has been granted access in the policy store. If the user is not yet authenticated, and the page is not granted to the anonymous-role, then the application displays the login page or form. If the user has been authenticated, but does not have permission, a security error is displayed. If you do not configure the policy store with appropriate grants, the pages will remain protected and therefore stay unavailable to the authenticated user.

Figure 30-27 illustrates the authorization process.

Figure 30-27 ADF Security Authorization

ADF security authorization process

The user is a member of the application role staff defined in the policy store. Because the user has not yet logged in, the security context does not have a subject (a container object that represents the user). Instead, Oracle Platform Security Services provides ADF Security with a subject with the anonymous user principal (a unique definition of the user) and the anonymous-role principal.

With the anonymous-role principal, typically the user would be able to access only pages not defined by ADF resources, such as the public.jsp page, whereas all pages that are defined either by an ADF task flow or outside of a task flow using an ADF page definition file are secure by default and unavailable to the user. An exception to this security policy would be if you were to grant anonymous-role access to ADF resources in the policy store. In this case, the user would not be allowed immediate access to the page defined by an ADF resource.

When the user tries to access a web page defined by an ADF resource, such as mypage.jspx (which is specified by an ADF page definition, for example), the ADF Security enforcement logic intercepts the request and because all ADF resources are secured by default, the user is automatically challenged to authenticate (assuming that the anonymous-role is not granted access to the ADF resource).

After successful authentication, the user will have a specific subject. The security enforcement logic now checks the policy store to determine which role is allowed to view mypage.jspx and whether the user is a member of that role. In this example for mypage.jspx, the view privilege has been granted to the staff role and because the user is a member of this role, they are allowed to navigate to mypage.jspx.

Similarly, when the user tries to access secpage.jsp, another page defined by ADF resources, for which the user does not have the necessary view privilege, access is denied.

Users and roles are those already defined in the identity store of the resource provider. Application roles are defined in the policy store of the jazn-data.xml file.

30.9 Preparing the Secure Application for Deployment

After testing in JDeveloper using Integrated WebLogic Server, you will eventually want to deploy the application to a standalone server. Initially, the server you target will be your staging environment where you can continue development testing using that server's identity store before deploying to the production environment. Thus, you will typically not migrate the test users you created to run with Integrated WebLogic Server. The steps you perform to migrate security policies and system credentials (from the cwallet.sso file) to standalone Oracle WebLogic Server will depend on the configured mode of the target server and whether you deploy using JDeveloper or a tool outside of JDeveloper.


Note:

For details about deploying from JDeveloper to a development environment, see Section 36, "Deploying Fusion Web Applications."


When the target server is configured for development mode, you can deploy directly from JDeveloper. In this case, JDeveloper automatically handles the migration of the policy store, system credentials, and identity store (users and groups) as part of the deployment process. Application security deployment properties are configured by default to allow the deployment process to overwrite the domain-level policy store and the system credentials. Additionally, the identity store deployment property is configured by default to migrate the identity store consisting of your test users. You can change this default deployment behavior in the Application Properties dialog, as described in Section 30.8.1, "How to Configure, Deploy, and Run a Secure Application in JDeveloper."


Note:

Note that migration of system credentials to Oracle WebLogic Server running in development mode will be performed only if the target server is configured to permit credential overwrite. For details about configuring Oracle WebLogic Server to support overwriting of system credentials, see the Oracle Fusion Middleware Application Security Guide.


When the target server is configured for production mode, you typically handle the migration task outside of JDeveloper using tools like Oracle Enterprise Manager. For details about using tools outside of JDeveloper to migrate the policy store to the domain-level in a production environment, see the Oracle Fusion Middleware Application Security Guide. Note that Oracle WebLogic Server running in production mode does not support the overwriting of system credentials under any circumstances.

Before you deploy the application, you will want to remove the test-all application role if you enabled the automatic grants feature in the Configure ADF Security wizard. Because the test-all role makes all ADF resources public, its presence increases the risk that your application may leave some resources unprotected. You must therefore remove the role before you migrate application-level policy store.

Additionally, when you prepare to deploy the application to Oracle WebLogic Server, you will want to remove the test identities that you created in the jazn-data.xml file. This will ensure that users you created to test security policies are not migrated to the domain-level identity store.


Best Practice:

If you deploy your application to the standalone environment, you must not migrate users and enterprise roles in your local identity store that are already configured for Oracle WebLogic Server. For example, if you were to deploy the identity store with the user weblogic and enterprise role Administrators, you would overwrite the default administration configuration on the target server. To ensure you avoid all possible conflicts, you can disable migration of the identity store, as described in Section 30.9.2, "How to Remove Test Users from the Application Identity Store."


30.9.1 How to Remove the test-all Role from the Application Policy Store

The jazn-data.xml file overview editor provides the facility to display all resources with view grants made to ADF Security's built-in test-all role. You can use this feature in the overview editor to delete the test-all role grant and replace it with a grant to the roles that your application defines.

Alternatively, you could delete the test-all role using the overview editor for the jazn-data.xml file, by selecting the test-all role in the Application Roles page of the editor and clicking the Delete Application Role button. However, when you remove the test-all role this way, you will still need to create a grant to replace the ones that you delete. Because the overview editor lets you combine both of these tasks, the following procedure describes its usage.

To remove the test-all application role and substitute custom application roles:

  1. From the Application menu, choose Secure > Resource Grants.

  2. In the Resource Grants page of the jazn-data.xml file overview editor, select Task Flow from the Resource Types dropdown list and then select the Show task flows with test-all grants only checkbox to view the list of task flows with grants to this built-in role.

    If no grant exists for the test-all role, then the Resources list in the overview editor will appear empty. The test-all role is defined only when enabled in the Configure ADF Security wizard. If it is enabled, you will see those task flows with test-all grants listed, as shown in Figure 30-28.

    Figure 30-28 Showing Task Flows with test-all Grants in the Overview Editor

    Shows test-all grants in ADF policy editor
  3. In the Resources column, select the first task flow in the list.

  4. In the Granted to column, select test-all and click the Remove Grantee icon.

  5. In the Granted to column, click the Add Grantee icon and choose Add Application Role and then use the Select Application Roles dialog to add the desired role.

  6. Repeat these steps to remove the test-all role and substitute your own application role for all remaining task flows.

  7. In the Resource Grants page of the overview editor, select Web Page from the Resource Types dropdown list and repeat these steps to remove the test-all role for all web pages and their ADF page definitions.

  8. With the Show task flows/web pages with test-all grants only checkbox selected, verify that the overview editor displays no resources with test-all grants.

30.9.2 How to Remove Test Users from the Application Identity Store

The standalone Oracle WebLogic Server that you will deploy to will have its own identity stored already configured. To ensure that you do not migrate test users and enterprise role groups you created in JDeveloper to the domain level, you should remove the test user realm from the jazn-data.xml file.

Alternatively, if you are deploying from JDeveloper, you can disable the migration of users and groups by deselecting the Users and Groups option in the Application Properties dialog, as described in Section 30.8.1, "How to Configure, Deploy, and Run a Secure Application in JDeveloper."

To remove test users and enterprise role groups from the identity store:

  1. From the Application menu, choose Secure > Users.

  2. In the editor window for the jazn-data.xml file, click the Source tab.

  3. In the source for the jazn-data.xml file, click the - icon to the left of the <jazn-realm> element so the entire element appears collapsed as shown in Figure 30-29.

    Figure 30-29 Selecting the <jazn-realm> Element in the XML Editor

    Source editor with jazn-realm selected
  4. With the element selected, press Delete and save the file.

30.10 Disabling ADF Security

JDeveloper allows you to disable ADF Security when you want to temporarily run the application without enforcing authorization checks against the application policy store. This will allow you to run the application and access all resources without the protection provided by existing security policies.

30.10.1 How to Disable ADF Security

To disable ADF Security at the level of your application, run the wizard and choose one of these options:

  • ADF Authentication disables ADF authorization but leaves the ADF authentication servlet enabled. For example, you may want to run your application in JDeveloper with authorization checking against security policies temporarily disabled. This option will require the user to log in the first time a page in the application is accessed by mapping the Java EE application root "/" to the allPages Java EE security constraint that will trigger user authentication. ADF resources will not be security-aware because authorization checking is not enforced. Thus, once the user is logged in, all web pages containing ADF resources will be available to the user.

  • Remove ADF Security Configuration disables the ADF authentication servlet and disables authorization checking on ADF resources. In this case, you can run the application with no user authentication and no security for ADF resources in place.

You may select either option with the intention of reenabling ADF Security at any time. The wizard specifically does not alter the application policy store that contains the security policies that application developers defined for ADF resources. This means that you can return to the wizard at any time, select the ADF Authentication and Authorization option, and reenable ADF Security against your application's existing policy store and identity store.

To disable Oracle ADF authorization checking:

  1. From the Application menu, choose Secure > Configure ADF Security.

  2. In the ADF Security page, select either the ADF Authentication option or the Disable ADF Security Configuration option. Click Next.

    After you run the wizard with either of these options, the ADF resources of your user interface projects will no longer be security-aware.

  3. Click Finish.

30.10.2 What Happens When You Disable ADF Security

If you run the Configure ADF Security wizard with the Remove ADF Security Configuration option selected, it removes the ADF-specific metadata in the web.xml file and adf-config.xml file, as described in Table 30-2.

Similarly, running the wizard with the ADF Authentication option selected to disable only authorization checking performs the following updates:

  • Leaves the ADF-specific metadata in the web.xml file unchanged and adds the allPages security constraint.

    With the allPages security constraint present, users will be expected to authenticate when they first access the application.

  • Sets the authorizationEnforce parameter in the <JaasSecurityContext> element of the adf-config.xml file to false, as shown in Example 30-20.

Example 30-20 AuthorizationEnforce Flag Disabled in the adf-config.xml FIle

<JaasSecurityContext 
  initialContextFactoryClass="oracle.adf.share.security.JAASInitialContextFactory"
  jaasProviderClass="oracle.adf.share.security.providers.jps.JpsSecurityContext"
                             authorizationEnforce="false"
                             authenticationRequire="true"/>

The adf-config.xml file is located in the /.adf/META_INF folder of your workspace. In JDeveloper, you can locate the file in the Application Resources panel of the Application Navigator by expanding the Descriptors-ADF META-INF node. Note that if you view the adf-config.xml file in an editor outside of JDeveloper, you must save the workspace to see the wizard-applied changes in the file.

30.11 Advanced Topics and Best Practices

After you have completed the process of enabling ADF Security, you may want to customize your application to work with ADF Security in the user interface. For example, you can use Expression Language (EL) to render UI components in the web page based on evaluation of custom permissions that you define just for a group of UI components. Additionally, you can define methods within a managed bean to expose information, such as the user name and role membership, in your application.

30.11.1 Using Expression Language (EL) with ADF Security

You can use Expression Language (EL) to evaluate the policy directly in the UI, while the use of Java enables you to evaluate the policy from within a managed bean. ADF Security implements several convenience methods for use in EL expressions to access ADF resources in the security context. For example, you can use the EL expression convenience methods to determine whether the user is allowed to access a particular task flow. Good security practice dictates that your application should hide resources and capabilities for which the user does not have access. And for this reason, if the user is not allowed access to a particular task flow, you would evaluate the user's permission grant to determine whether or not to render the navigation components that initiate the task flow.


Note:

The ability to evaluate a policy is limited to the current request. For this reason, it is important to understand where the policy evaluation occurs, because evaluating the policy at anything other than the request scope can lead to unexpected results.


30.11.1.1 How to Evaluate Policies Using EL

The use of EL within a UI element allows for properties to be defined dynamically, resulting in modification of the UI component at runtime. In the case of securing resources, the UI property of interest is the Rendered property, which allows you to show and hide components based on available permissions. By default, the Rendered property is set to true. By dynamically changing this value based on the permission, you can set the UI component to be shown or hidden. For example, if the user has the appropriate permission, the Rendered property should be set to true so that the UI component is shown. If they do not have permission, the property should be set to false and the UI component hidden from view.

To evaluate a policy using EL, you must use the ADF Security methods in the securityContext EL namespace. These methods let you access information in the ADF security context for a particular user or ADF resource.

Table 30-9 shows the EL expression that is required to determine whether a user has the associated permission. If the user has the appropriate permission, the EL expression evaluates to true; otherwise, it returns false.

Table 30-9 EL Expression to Determine View Permissions on ADF Resources

ExpressionExpression action
#{securityContext.taskflowViewable['MyTaskFlow']}

For example:

#{securityContext.taskflowViewable
 ['/WEB-INF/audit-expense-report.xml#audit-expense-report']}

Where MyTaskFlow is the WEB-INF node-qualified name of the task flow being accessed. Returns true if the user has access rights. Returns false if the user does not have sufficient access rights.

#{securityContext.regionViewable['MyPagePageDef']}

Where MyPagePageDef is the qualified name of the page definition file associated with the web page being accessed. Returns true if the user has access rights. Returns false if the user does not have sufficient access rights.



Note:

In the case of page permission, the value of the page definition can be specified dynamically by using late-binding EL within a managed bean, as described in Section 30.3.7, "What You May Need to Know About the valid-users Role."


Table 30-10 shows the EL expression that lets you get general information from the ADF security context not related to a particular ADF resource. For example, you can access the current user name when you want to display the user's name in the user interface. You can also check whether the current user is a member of certain roles or granted certain privileges. Your application may use this result to dynamically hide or show menus.

Table 30-10 EL Expression to Determine User Information in the ADF Security Context

ExpressionExpression Action
#{securityContext.userName}

Returns the user name of the authenticated user.

#{data.adfContext.tenantName}

Returns the tenant name of the authenticated user. The tenant name is an alias that the user knows for themselves and can use to login.

#{data.adfContext.tenantId}

Returns the tenant ID of the authenticated user.

#{securityContext.authenticated}

Returns true if the user is logged in. Returns false if the user is not logged in. This is useful for rendering a dynamic link for login/logout, or for rendering a "Welcome, username" message when the user has been authenticated. For an example that uses this expression, see Section 30.7.4.2, "Adding Login and Logout Links."

#{securityContext.userInRole['roleList']}

Where roleList is a comma-separated list of role names. Returns true if the user is in at least one of the roles. Returns false if the user is in none of the roles, or if the user is not currently authenticated.

#{securityContext.userInAllRoles['roleList']}

Where roleList is a comma-separated list of role names. Returns true if the user is in all of the roles. Returns false if the user is not in all of the roles, or if the user is not currently authenticated.

#{securityContext.userGrantedPermission['permission']}

Where permission is a string containing a semicolon-separated concatenation of permissionClass=<class>;target=<artifact_name>;action=<action>. Returns true if the user has access rights. Returns false if the user does not have sufficient access rights.

Note that the convenience methods taskflowViewable and regionViewable shown in Table 30-9 provide the same functionality.

#{securityContext.userGrantedResource['resource']}

Where resource is a string containing a semicolon-separated concatenation of resourceName=<name>;resourceType=<type>;action=<action>. Returns true if the user has access rights. Returns false if the user does not have sufficient access rights.

You can use this expression to test the permission grant in the rendered property of a resource that is not contained in a task flow (like an ADF Faces panel). This provides an alternative to creating a custom permission class that must be packaged with the application.

For example, when you want to show or hide a panel in a page based on the permission granted to that resource, the expression might look like:

#{securityContext.userGrantedResource
     ['resourceName=myPanel1;
       resourceType=myLayoutPanel;
       action=myAction']}

In the policy store, a grant to the resource has a <permission> definition like:

<permission>
  <class>oracle.security.jps.
      ResourcePermission</class>
  <name>resourceType=myLayoutPanel,
      resourceName=myPanel1</name>
  <actions>myAction</actions>
</permission>

To associate the rendering of a navigation component with a user's granted permissions on a target task flow or page definition:

  1. In the Application Navigator, double-click the page.

  2. Select the component that is used to navigate to the secured page.

  3. In the Property Inspector, select Expression Builder from the dropdown menu displayed to the right of the Rendered property, as shown in Figure 30-30.

    Figure 30-30 Binding the Rendered Property to Data

    Rendered Property usage
  4. In the Expression Builder, expand the ADF Bindings - securityContext node and select the appropriate EL value, then in the Expression field, enter the qualified name of the ADF resource that the user will attempt to access.

    For example, as shown in Figure 30-31, to limit access to a task flow that your application displays, you would create an expression like:

    #{securityContext.taskflowViewable
         ['/WEB-INF/audit-expense-report.xml#audit-expense-report']}
    

    In this example, the expression determines the user's access rights to view the target task flow audit-expense-report. If the user has the access rights, then the expression evaluates to true and the rendered property receives the value true.

    Figure 30-31 Defining EL in the Expression Builder Dialog

    Rendered property and EL usage
  5. Click OK.

When you run the application, the component will be rendered or hidden based on the user's ability to view the target page.

30.11.1.2 What Happens When You Use the Expression Builder Dialog

When you use the Expression Builder to define an expression for the Rendered property in the Property Inspector, JDeveloper updates the component definition in the open .jspx file. The component's rendered property appears with an expression that should evaluate to either true or false, as shown in Example 30-21. In this example, the component is a navigation link with the link text Checkout defined by another expression. The page that contains the navigation link renders the component only when the user has sufficient rights to access the checkout task flow.

Example 30-21 EL Expression in Source for .jspx File

<af:commandNavigationItem
   text="#{res['global.nav.checkout']}"
   action="globalCheckout"
   id="cni3"
   rendered="#{securityContext.taskflowViewable
                       ['/WEB-INF/checkout-task-flow.xml#checkout-task-flow']}"
/>

30.11.1.3 What You May Need to Know About Delayed Evaluation of EL

The ability to evaluate a security permission is scoped to the request. If you want to evaluate permissions to access a target page from a managed bean that is scoped to a higher level than request (for example, a global menu that is backed by a managed bean), you must implement delayed EL evaluation (late-binding). By passing in the target page as a managed property of the bean, you ensure that the EL expression is evaluated only after the required binding information is available to the managed bean. Because EL is evaluated immediately when the page is executed, placing the EL expression directly in the properties of a UI component, backed by a managed bean, would result in an out-of-scope error.

Example 30-22 shows a property (authorized) of a managed bean that returns true or false based on a user's ability to view a named target page. In this case, the _targetPageDef variable is a managed property containing the name of the target page. Within the UI, the EL expression would reference the authorized property.

Example 30-22 Delayed EL Evaluation in a Managed Bean

public boolean isAuthorized() 
{
 if (_targetPageDef != null) {
  FacesContext fctx = FacesContext.getCurrentInstance();
  ADFContext adfCtx = ADFContext.getCurrent();
  SecurityContext secCtx = adfCtx.getSecurityContext();
  boolean hasPermission = secCtx.hasPermission(new RegionPermission
     (_targetPageDef, RegionPermission.VIEW_ACTION));
     if (hasPermission) {
        return hasPermission;
     }
     else {
        fctx.addMessage(null, new FacesMessage (
        FacesMessage.SEVERITY_WARN, "Access Permission not defined! " , null));
        return false;
     }
}

30.11.2 How to Evaluate Policies Using Custom JAAS Permissions and EL

You can use the value userGrantedPermission in the ADF Security EL namespace described in Table 30-9 to determine whether to render UI elements in your page. The expression you create can evaluate custom permission grants for the authenticated user. A custom permission is a JAAS Permission class that you create using the Create JAAS Permission dialog. The dialog helps you create a class that extends the oracle.adf.share.security.authorization.ADFPermission class to ensure that the permission can be used by ADF Security.

Custom permissions in the Fusion web application give you additional flexibility to define security policies. For example, you might name a custom permission to correspond to the UI element you want to protect. Once you create the permission, you use the jazn-data.xml file overview editor to create a security policy for the ADF resource by granting permission to the application roles that your jazn-data.xml policy store defines.


Best Practice:

Custom ADF permission classes let you extend ADF Security to define custom actions for use in grants. This gives you the flexibility to define security policies to manage the user's ability to view UI components without having to overload the built-in actions defined by the ADF resources' permission classes. Be aware that you do not need to create custom permissions to manage access to web pages. This level of access is provided by the default ADF Security view permission that you work with in the jazn-data.xml file overview editor.


To create the custom JAAS Permission class:

  1. In the Application Navigator, right-click the project where you want to create the custom JAAS Permission class and choose New.

  2. In the New Gallery, select All Items and then JAAS Permission, and click OK.

  3. In the Create JAAS Permission dialog, enter the name of the permission and the fully qualified package name.

    The permission name you choose can be a generic name.

  4. In the Actions list, enter the name that you want to use for the action grant.

    The action name can be a specific name that helps you to identify the permission's purpose. You can add more than one action to the list when you want the permission to apply to the same component, but for different purposes. For example, you might allow a manager and an employee to both view a page menu, but you might want the manager to also be able to choose specific menu items.

  5. In the Targets list, leave the selection Attribute unchanged.

    You will specify the actual target name when you create the policy in the policy store using the custom JAAS Permission's action.

  6. Click OK.

    JDeveloper adds to the class to the package you specified. For example, the oracle.fodemo.storefront.store.view package of the Fusion Order Demo application defines a custom permission class AccountPermission.java that looks like this:

    package oracle.fodemo.storefront.store.view;
    
    import oracle.adf.share.security.authorization.ADFPermission;
    import oracle.adf.share.security.authorization.PermissionActionDescriptor;
    import oracle.adf.share.security.authorization.PermissionTargetDescriptor;
    
    public class AccountPermission extends ADFPermission {
      private static final PermissionActionDescriptor[] actions =
       {new PermissionActionDescriptor("view", "view")};
      private static final PermissionTargetDescriptor[] targets =
       {new PermissionTargetDescriptor("attributeValue", "Attribute")};
    
      public AccountPermission(String name, String actions) {
        super(name, actions);
      }
    
      public static PermissionActionDescriptor[] getPermissionActionDescriptors() {
        return actions;
      }
    
      public static PermissionTargetDescriptor[] getPermissionTargetDescriptors() {
        return targets;
      }
    }
    

To create the ADF security policy using the custom permission:

  1. In the main menu, choose Application and then Secure > Resource Grants.

  2. In the Resource Grants page of the jazn-data.xml file overview editor, select the custom resource from the Resource Types dropdown list.

    The overview editor displays all custom resources. Initially, the custom resource will not have a resource type associated with it and the editor highlights this, as shown in Figure 30-32.

    Figure 30-32 Displaying a Custom Resource in the Overview Editor

    Custom resource with no resource type
  3. Next to the Resource Type field, click the New Resource Type icon.

  4. In the Create Resource Type dialog, enter the name and action and click OK.

  5. In Resource Grants page of the overview editor, in the Granted to column, click the Add Grantee icon and choose Add Application Role.

  6. In the Select Application Roles dialog, select the application role and click OK.

  7. In the Resource Grants page of the overview editor, in the Actions column, select desired action.

    The overview editor displays the custom permission grant, as shown in Figure 30-33.

    Figure 30-33 Creating a Custom Permission Grant in the Overview Editor

    Custom resource with no resource type

To associate the rendering of a UI component with a user's granted custom permission:

  1. In the Application Navigator, double-click the page.

  2. Select the component that is used to navigate to the secured page.

  3. In the Property Inspector, select Expression Builder from the dropdown menu displayed to the right of the Rendered property.

  4. In the Expression Builder, expand the ADF Bindings - securityContext node and select the userGrantedPermission value, then, in the Expression field, enter a concatenated string that defines the permission.

    Enter the permission string as a semicolon-separated concatenation of permissionClass=qualifiedClassName;target=artifactName;action=actionName. For example, to protect an account number that a text field displays in a page, you would enter an expression like the following, where the permission for userGrantedPermission is the same name as the custom JAAS permission grant:

    #{securityContext.userGrantedPermission
           ['permissionClass=oracle.fodemo.storefront.store.view.AccountPermission;
             target=AccountPermission;action=view']}
    

    In this example, the expression evaluates the permission based on the custom JAAS permission definition named AccountPermission that you added to the application policy store.

    In the Fusion Order Demo application, the page myOrders.jpx defines the userGrantedPermission expression on the Value property of the af:outputText#ot18 text field, as shown in Figure 30-34. In this case, the expression tests whether the user has permission then either displays the account number (through bindings.AccountNumber.inputValue) or, when the user does not have permission, displays XXXXXXXXXXXX in place of the account number. Because the expression is not defined on the text field's Rendered property, the page always displays the field.

    #{securityContext.userGrantedPermission
           ['permissionClass=oracle.fodemo.storefront.store.view.AccountPermission;
             target=AccountPermission;action=view']
         ? bindings.AccountNumber.inputValue : 'XXXXXXXXXXXX'}
    

    Figure 30-34 Defining EL in the Expression Builder Dialog

    Shows expression in Expression Builder
  5. Click OK.

When you run the application, the component will be rendered or hidden based on the user's ability to view the target page.

30.11.3 Getting Information from the ADF Security Context

The implementation of security in a Fusion web application is by definition an implementation of the security infrastructure of the ADF Security framework. As such, the security context of the framework allows access to information that is required as you define the policies and the overall security for your application.

30.11.3.1 How to Determine Whether Security Is Enabled

Because the enforcement of ADF Security can be turned on and off at the container level independent of the application, you should determine whether ADF Security is enabled prior to making authorization checks. You can achieve this by calling the isAuthorizationEnabled() method of the ADF security context, as shown in Example 30-23.

Example 30-23 Using the isAuthorizationEnabled() Method of the ADF Security Context

if (ADFContext.getCurrent().getSecurityContext().isAuthorizationEnabled()){
  //Authorization checks are performed here.
}

30.11.3.2 How to Determine Whether the User Is Authenticated

As the user principal in a Fusion web application is never null (that is, it is either anonymous for unauthenticated users or the actual user name for authenticated users), it is not possible to simply check whether the user principal is null to determine if the user has logged on or not. As such, you must use a method to take into account that a user principal of anonymous indicates that the user has not authenticated. You can achieve this by calling the isAuthenticated() method of the ADF security context, as shown in Example 30-24.

Example 30-24 Using the isAuthenticated() Method of the ADF Security Context

// ============ User's Authenticated Status =============
private boolean _authenticated;
public boolean isAuthenticated() {
_authenticated = ADFContext.getCurrent().getSecurityContext().isAuthenticated();
    return _authenticated;
}

30.11.3.3 How to Determine the Current User Name, Tenant Name, or Tenant ID

Fusion web applications support the concept of public pages that, while secured, are available to all users. Furthermore, components on the web pages, such as portlets, require knowledge of the current user identity. As such, the user name in a Fusion web application will never be null. If an unauthenticated user accesses the page, the user name anonymous will be passed to page components. When the Fusion web application registers an tenant name for the user, the tenant name may also be obtained. The tenant name is an alias that the user knows for themselves and can use to login.

You can determine the current user's name by evaluating the getUserName() method of the ADF security context, as shown in Example 30-25. This method returns the string anonymous for all unauthenticated users and the actual authenticated user's name for authenticated users.

Example 30-25 Using the getUserName() Method of the ADF Security Context

// ============ Current User's Name/PrincipalName =============
public String getCurrentUser() {
   _currentUser = ADFContext.getCurrent().getSecurityContext().getUserName();
   return _currentUser;
}

Because the traditional method for determining a user name in a Faces-based application (FacesContext.getCurrentInstance().getExternalContext().getRemoteUser()) returns null for unauthenticated users, you need to use additional logic to handle the public user case if you use that method.

You can determine the current user's tenant name by evaluating the getTenantName() method of the ADF security context, as shown in Example 30-26.

Example 30-26 Using the getTenantName() Method of the ADF Security Context

// ============ Current User's Tenant Name =============
public String getTenantName() {
  _tenantName = ADFContext.getCurrent().getTenantName();
  return _tenantName;
}

You can determine the current user's tenant ID by evaluating the getTenantId() method of the ADF security context, as shown in Example 30-27. This method returns the string anonymous for all unauthenticated users and the actual authenticated user's name for authenticated users.

Example 30-27 Using the getTenantId() Method of the ADF Security Context

// ============ Current User's Tenant ID =============
public String getTenantId() {
    _tenantId = ADFContext.getCurrent().getTenantId();
    return _tenantId;
}

30.11.3.4 How to Determine Membership of a Java EE Security Role

As Fusion web applications are JavaServer Faces-based applications, you can use the isUserInRole(roleName) method of the Faces external context, as shown in Example 30-28, to determine whether a user is in a specified role. Because ADF Security is based around JAAS policies, you should not need to use Java EE security roles to secure pages associated with ADF security-aware resources based on role membership. However, you might use the method to check the role for a page that is not associated with an ADF security-aware resource.

In this example, a convenience method (checkIsUserInRole) is defined. The use of this method within a managed bean enables you to expose membership of a named role as an attribute, which can then be used in EL.

Example 30-28 Using the isUserInRole(roleName)) Method of the Faces Context

public boolean checkIsUserInRole(String roleName){
        return 
(FacesContext.getCurrentInstance().getExternalContext().isUserInRole(roleName));
}

public boolean isCustomer() {
        return (checkIsUserInRole("fod-users"));
}

30.11.3.5 How to Determine Permission Using Java

To evaluate the security policies from within Java, you can use the hasPermission method of the ADF security context. This method takes a permission object (defined by the resource and action combination) and returns true if the user has the corresponding permission.

In Example 30-29, a convenience function is defined to enable you to pass in the name of the page and the desired action, returning true or false based on the user's permissions. Because this convenience function is checking page permissions, the RegionPermission class is used to define the permission object that is passed to the hasPermission method.

Example 30-29 Using the hasPermission() Method to Evaluate Access Policies

private boolean TestPermission (String PageName, String Action)  {
  Permission p = new RegionPermission("view.pageDefs." + PageName + "PageDef", 
Action); if (p != null) { return ADFContext.getCurrent().getSecurityContext().hasPermission(p); } else { return (true); }

As it is possible to determine the user's permission for a target page from within a backing bean, you can use this convenience method to dynamically alter the result of a Faces navigation action. In Example 30-30, you can see that a single command button can point to different target pages depending on the user's permission. By checking the view permission from the most secured page (the manager page) to the least secured page (the public welcome page), the command button's backing bean will apply the appropriate action to direct the user to the page that corresponds to their permission level. The backing bean that returns the appropriate action is using the convenience method defined in Example 30-29.

Example 30-30 Altering a Page Navigation Result Based on an Authorization Check

//CommandButton Definition
<af:commandButton text="Goto Your Group Home page"
  binding="#{backing_content.commandButton1}"
  id="commandButton1"

  action="#{backing_content.getSecureNavigationAction}"/>

//Backing Bean Code
    public String getSecureNavigationAction() {
      String ActionName;
      if (TestPermission("ManagerPage", "view"))
        ActionName = "goToManagerPage";
      else if (TestPermission("EmployeePage", "view"))
        ActionName = "goToEmployeePage";
      else
        ActionName = "goToWelcomePage";
      return (ActionName);
    }

30.11.4 Best Practices for Working with ADF Security

These best practices summarize the rules that govern enforcement of security by the ADF Security framework. Understanding these best practices will help you to secure the application to allow users to access the web pages you intend.

Do build your application with ADF Security enabled from the start.

When you enable security, you essentially lock down the application and you will be required to make explicit permission grants to specific ADF security-aware resources you create. Knowing about these resources and making grants on them as you build the application will enable you to iteratively test security to ensure that you structure your application in a way that achieves the desired result.

Do define permission grants for bounded task flows.

Pages that the user accesses within the process of executing a bounded task flow will not be individually permission-checked and will run under the permission grants of the task flow. This means that any page that you add to the task flow should not have its own page definition-level security defined. Upon requesting a flow, the user will be allowed either to view all the pages of the task flow or to view none of the pages, depending on their level of access.

Do not define permission grants for individual pages of a bounded task flow.

It is important to realize that task flows do not prevent users from accessing pages directly. Any web page that is located in a directory that is publicly accessible can be reached from a browser using a URL. To ensure that pages referenced by a bounded task flow cannot be accessed directly, remove all permission grants that exist for their associated page definition file. When pages require additional security within the context of a bounded task flow, wrap those pages in a sub-task flow with additional grants defined on the nested task flow.

Do use task flows to reduce the number of access points exposed to end users.

When you use task flows you can reduce the number of access points that you expose to end users. For example, configure an unbounded task flow to display one page that provides navigation to the remaining pages in your application. Use bounded task flows for the remaining pages in the application. By setting the URL Invoke property of these bounded task flows to url-invoke-disallowed, your application has one access point (the page on the unbounded task flow). For more information about the URL Invoke property, see Section 15.6.4, "How to Call a Bounded Task Flow Using a URL."

Do define permission grants for individual pages outside of a bounded task flow.

Page-level security is checked for pages that have an associated page definition binding file only if the page is directly accessed or if the page is accessed in an unbounded task flow. There is a one-to-one relationship between the page definition file and the web page it secures.

If you want to secure a page that uses no ADF bindings, you can create an empty page definition binding file for the page.

Do define custom permissions to render UI component based on the user's access rights.

Custom ADF permission classes let you extend ADF Security to define custom actions for use in grants. This gives you the flexibility to define security policies to manage the user's ability to view UI components without having to overload the built-in actions defined by the ADF resources' permission classes.

Do define entity object attribute permissions to manage the user's access rights to row-level data displayed by UI components.

Entity objects and entity object attributes both define permission classes that let you define permissions for the read, update, and delete operations that the entity object initiates on its data source. In the case of these model project components, you must explicitly grant permissions to an application role in order to opt into ADF Security authorization. However, once you enable authorization for an entity object, all rows of data defined by the entity object will be protected by the grant. At this level of granularity, your table component would render in the web page either with all data visible or with no data visible—depending on the user's access rights. As an alternative to securing the entire collection, you can secure individual columns of data. This level of granularity is supported by permissions you set on the individual attributes of entity objects. When entity objects are secured, users may see only portions of the data that the table component displays.

Do use task flow or page-level permission grants to avoid exposing row-level create/insert operations to users with view-only permission.

The correct way to control access to a page that should allow only certain users to update new rows in a table is to use task flow or page-level permission grants. However, as an alternative, it is possible to secure table buttons corresponding to particular operations by specifying an EL expression to test the user's access rights to view the button. When the custom permission is defined and the userGrantedPermission expression is set on the Rendered property of the button, only users with sufficient privileges will see the button. This may be useful in a case where the user interface displays a page that is not restricted and view-only permission for row-level data is defined for the entity object. In this case, when viewed by the user, the Delete button for the editable table associated with the entity object will appear disabled. However, in the case of an input table, the user interface does not disable the button for the CreateInsert operation even though the user may not have update permission.

Do not use JDeveloper as a user identity provisioning tool.

JDeveloper must not be used as an identity store provisioning tool, and you must be careful not to deploy the application with user identities that you create for testing purposes. Deploying user identities with the application introduces the risk that malicious users may gain unintended access. Instead, always rely on the system administrator to configure user identities through the tools provided by the domain-level identity management system. You should delete all users and groups that you create in the jazn-data.xml file before deploying the application.

Do not allow users to access a web page by its file name.

When you deploy the Fusion web application, you should always permit users to access the web page from a view activity defined in the ADF Controller configuration file. Do not allow users to access the JSPX file directly by its physical name (for example, similar to the file name AllDepartments.jspx.

Assuming the view activity is named AllDepartments, then there are two ways to call the page:

  1. localhost:7101/myapp/faces/AllDepartments

  2. localhost:7101/myapp/faces/AllDepartments.jspx

The difference is that the call 1) is in the context of the ADF Controller task flow, which means that navigation on the page will work and any managed beans that are referenced by the page will be properly instantiated. The call in 2) also serves the page, however, the page may not function fully. This may be considered a security breach.

To prevent direct JSPX file access, move the JSPX file under the /public_html/WEB-INF directory so that direct file access is no longer possible. To access a document, users will have to call its view activity name.

Note that this suggestion does not protect documents that are unprotected in ADF Security. It only helps to lock down access to the physical file itself.

Thus, the following security guidelines still apply:

  1. Apply ADF Security permissions to all JSPX documents associated with view activities defined in the adfc-config.xml file.

  2. Move all JSPX documents in the user interface project under the /public_html/WEB-INF directory to prevent direct file access.

  3. Limit the pages in the adfc-config.xml to the absolute minimum and place all other pages into bounded task flows.

  4. Make bounded task flows inaccessible from direct URL access (which is the default configuration setting for new task flows).

  5. Apply ADF Security permissions to bounded task flows.

PK0̲PKHwEOEBPS/graphs_charts.htm Creating Databound ADF Data Visualization Components

26 Creating Databound ADF Data Visualization Components

This chapter describes how to use the Data Controls panel and ADF data binding to create databound ADF Data Visualization components. These components allow you to display and analyze data through a wide variety of graphs, several kinds of gauges, a pivot table, geographic maps with multiple layers of information, several kinds of Gantt charts, timelines, a hierarchy viewer, treemaps, and sunbursts.

This chapter includes the following sections:

26.1 Introduction to Creating ADF Data Visualization Components

ADF Data Visualization components provide extensive graphical and tabular capabilities for visually displaying and analyzing data.

Both ADF graph and gauge components render graphical representations of data. However, graphs (which produce more than 50 types of charts) allow you to evaluate multiple data points on multiple axes in a variety of ways. Many graph types assist in the comparison of results from one group with the results from another group. In contrast, gauges focus on a single data point and examine that point relative to minimum, maximum, and threshold indicators to identify problems.

The ADF pivot table component produces a grid that supports multiple layers of data labels on the row edge or the column edge of the grid. An optional pivot filter bar uses a page edge to filter the pivot table data not in view. This component also provides the option of automatically generating subtotals and totals for grid data. Pivot tables let you pivot data layers from one edge to another to obtain different views of your data. For example, a pivot table might initially display total sales data for products within regions on the row edge, broken out by years on the column edge. If you pivot region and year at runtime, then you end up with total sales data for products within years, broken out by region. At runtime, end users can click buttons that appear in the inner column labels to sort rows in ascending or descending order.

The ADF geographic map component represents business data spatially, enabling you to superimpose multiple layers (also referred to as themes) of information on a single map. For example, a map of the United States might use a color theme that provides varying color intensity to indicate the popularity of a product within each state, a pie chart theme that shows sales within product category, and a point theme that identifies the exact location of each warehouse. When all three themes are superimposed on the United States map, you can easily evaluate whether there is sufficient inventory to support the popularity level of a product in specific locations.

There are three types of ADF Gantt chart components: the project Gantt chart (which focuses on project management), the scheduling Gantt chart, and the resource utilization Gantt chart (both of which focus on resource management). Each Gantt chart shows the following regions combined with a splitter:

An ADF timeline component is an interactive data visualization tool that allows users to view date-based events in chronological order and easily navigate forwards and backwards within a defined time range. A dual timeline can be used for a side-by-side comparison of events.

A timeline is composed of the display of events as timeline items along a time axis, a movable overview window that corresponds to the period of viewable time in the timeline, and an overview time axis that displays the total time increment for the timeline. A horizontal zoom control is available to change the viewable time range. Timeline items corresponding to events display associated information or actions and are connected to the date of the event in the time axis. Timelines items are represented by a marker in the overview panel. No more that two series of events are supported by the timeline component.

The ADF hierarchy viewer component produces a graphic that displays hierarchical data as a set of linked shapes. The shapes and links correspond to the elements and relationships in the data. For example, a hierarchy viewer component might be used to generate an organizational chart based on employee data. At runtime, end users can pan and zoom the graphic and expand, select, and navigate the management hierarchy that the graphic displays.

The ADF treemap and sunburst components display quantitative hierarchical data across two dimensions, represented visually by size and color. For example, you can use a treemap or sunburst to display quarterly regional sales and to identify sales trends, using the size of the node to indicate each region's sales volume and the node's color to indicate whether that region's sales increased or decreased over the quarter.

Each ADF Data Visualization component needs to be bound to data before it can be rendered because the appearance of the components is dictated by the data that is displayed. This chapter describes how to bind each component to a data source.

Figure 26-1 shows a number of the ADF Data Visualization components at runtime, including a bar graph, a pie chart graph, a status meter gauge, and a dial gauge.

Figure 26-1 Dashboard with ADF Data Visualization Components

Dashboard with ADF Data Visualization Components

26.2 Creating Databound Graphs

When you create a graph using a data collection inserted from the Data Controls panel, a Component Gallery allows you to choose from a wide number of graph categories, graph types, and layout options. Graph categories group together one or more types of graph. For example, the Scatter/Polar category includes the following types of graph:

Explore the Component Gallery that appears when you create a graph to view available graph categories, types, and descriptions for each one. Figure 26-2 shows the Component Gallery that appears for ADF graphs when you use the Data Controls panel.

Figure 26-2 ADF Graphs Component Gallery from Data Controls Panel

ADF Graphs Component Gallery

Note:

Some graph types require very specific kinds of data. If you bind a graph to a data collection that does not contain sufficient data to display the graph type requested, then the graph is not displayed and a message about insufficient data appears.


You can also create a graph by dragging a graph component from the Component Palette. This approach allows you the option of designing the graph user interface before binding the component to data. A Component Gallery appears to view graph types, descriptions, and quick layout options.


Note:

The ADF sparkchart can only be inserted from the Component Palette and bound to data afterwards. For more information, see Section 26.2.4, "How to Create a Databound Sparkchart."


Table 26-1 lists the categories that appear in the Component Gallery for graphs. Each category has one or more graph types associated with it.

Table 26-1 ADF Graph Categories in the Component Gallery

CategoryDescription

Area

Creates a graph in which data is represented as a filled-in area. Use area graphs to show trends over time, such as sales for the last 12 months. Area graphs require at least two groups of data along an axis. The axis is often labeled with time periods such as months.

Bar

Creates a graph in which data is represented as a series of vertical bars. Use to examine trends over time or to compare items at the same time, such as sales for different product divisions in several regions.

Bar (Horizontal)

Creates a graph that displays bars horizontally along the y-axis. Use to provide an orientation that allows you to show trends or compare values.

Bubble

Creates a graph in which data is represented by the location and size of round data markers (bubbles). Use to show correlations among three types of values, especially when you have a number of data items and you want to see the general relationships. For example, use a bubble graph to plot salaries (x-axis), years of experience (y-axis), and productivity (size of bubble) for your work force. Such a graph allows you to examine productivity relative to salary and experience.

Combination

Creates a graph that uses different types of data markers (bars, lines, or areas) to display different kinds of data items. Use to compare bars and lines, bars and areas, lines and areas, or all three.

Funnel

Creates a graph that is a visual representation of data related to steps in a process. The steps appear as vertical slices across a horizontal cylinder. As the actual value for a given step or slice approaches the quota for that slice, the slice fills. Typically a funnel graph requires actual values and target values against a stage value, which might be time. For example, use this component to watch a process (such as a sales pipe line) move towards a target across the stage of the quarters of a fiscal year.

Line

Creates a graph in which data is represented as a line, as a series of data points, or as data points that are connected by a line. Line graphs require data for at least two points for each member in a group. For example, a line graph over months requires at least two months. Typically a line of a specific color is associated with each group of data such as the Americas, Europe, or Asia. Use to compare items over the same time.

Pareto

Creates a graph in which data is represented by bars and a percentage line that indicates the cumulative percentage of bars. Each set of bars identifies different sources of defects, such as the cause of a traffic fatality. The bars are arranged by value, from the largest number to the lowest number of incidents. A pareto graph is always a dual-y graph in which the first y-axis corresponds to values that the bars represent and the second y-axis runs from 0 to 100% and corresponds to the cumulative percentage values. Use the pareto graph to identify and compare the sources of defects.

Pie

Creates a graph in which one group of data is represented as sections of a circle causing the circle to look like a sliced pie. Use to show relationship of parts to a whole such as how much revenue comes from each product line.

Radar

Creates a graph that appears as a circular line graph. Use to show patterns that occur in cycles, such as monthly sales for the last three years.

Scatter/Polar

Creates a graph in which data is represented by the location of data markers. Use to show correlation between two different kinds of data values such as sales and costs for top products. Scatter graphs are especially useful when you want to see general relationships among a number of items.

Sparkchart

Creates a simple, condensed graph that displays trends or variations, often in the column of a table, or inline with text. Sparkcharts are only available in the Component Gallery when inserted using the Component Palette and bound to data afterwards.

Stock

Creates a graph in which data shows the high, low, and closing prices of a stock. Each stock marker displays three separate values.


Figure 26-3 shows the horizontal bar graph that appears in the Hot Items Statistics page of the StoreFrontModule application. This graph displays the quantity of orders for each product so that you can easily identify the items that have been ordered most frequently.

Figure 26-3 Hot Items Statistics Graph

Hot items statistics graph

For information about customizing graphs after the data binding is completed, see the "Using ADF Graph Components" chapter in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

26.2.1 How to Create a Graph

Graphs are based on data collections. Using data controls in Oracle ADF, Oracle JDeveloper makes this a declarative task. You drag and drop a collection from the Data Controls panel.

To create a databound graph:

  1. From the Data Controls panel, select a collection.

    For example, to create the bar graph that displays the order count for each product in the Hot Items Statistics page of the StoreFrontModule application, select the ProductOrdersCount collection. Figure 26-4 shows the ProductOrdersCount collection in the Data Controls panel.

    Figure 26-4 Data Collection for Counting Product Orders

    Data collection for counting product orders
  2. Drag the collection onto a JSF page and, from the context menu, choose Graphs to display the Component Gallery.

  3. Select a graph category and a graph type from the Component Gallery and click OK.

    For information about the graph categories and graph types that appear in the Component Gallery, see Table 26-1.

    The name of the dialog and the input field labels that appears depends on the category and type of graph that you select. For example, if you select Bar (Horizontal) as the category and Bar as the type, then the name of the dialog that appears is Create Horizontal Bar Graph and the input field is labeled Bars.

  4. Do the following in the dialog to configure the graph to display data:

    • Drag attributes from the Available list to the Bars or X Axis input fields, depending on where you want the values for the attributes to appear at runtime.

    • In the Attribute Labels field, enter a value or select a value from the dropdown list in the Label column to specify the label that appears at runtime.

    • If you want to change the display of the data represented in the bars to the Y-Axis, click the Swap Bars with Y-Axis button. This action switches the hidden data layer between the graph series and groups and is not a simple manual swap of the bars and y-axis attributes.

    • If you want to change from the default selection of Typed Attributes to Name-Value Pairs to configure how data points are stored in a collection, then click the Change Data Shape button. A dialog appears that presents you with the following options:

      • Typed Attributes

        Each kind of data point in the collection is represented by a different attribute. This option is also valid when there is only a single kind of data point in the graph.

        For example, if you have data points for Estimated Value and Actual Value, then select Typed Attributes only if you have one attribute for the estimated value and a second attribute for the actual value.

      • Name-Value Pairs

        Indicates that there are multiple kinds of data points, but only a single attribute to designate these points. In this case, the single attribute has -values that identify each kind of data point.

        For example, the attribute might have the value EST for a data point that represents an estimated value and ACT for a data point that represents an actual value.

    • Select Set the current row for master-detail to use the graph's row selection listener to enable clicks on a bar, slice, or other graph data element to update the data in another ADF component. For more information see Section 26.2.3, "What You May Need to Know About Using a Graph's Row Selection Listener for Master-Detail Processing."

    Figure 26-5 shows the Create Horizontal Bar Graph dialog that generates a graph using data from the ItemsOrdered attribute in the ProductOrdersCount data collection. The ProductName attribute provides labels for the displayed data.

    Figure 26-5 Create Horizontal Bar Graph Dialog for ProductsOrderCount

    Create horizontal bar graph for ProductsOrderCount
  5. Optionally, click the Preview tab to display a live preview of the bar graph and its data. If necessary, go back to the Configuration tab so that you can adjust the bar graph specifications.

  6. Click OK.

After completing the data binding dialog, you can use the Property Inspector to specify settings for the graph attributes and you can also use the child tags associated with the graph tag to customize the graph further.


Note:

Use the emptyText attribute to specify the text to display when there is no data to return in the graph. The default message is No data to display. The attribute accepts HTML for formatting the message and an EL expression that evaluates to the viewable property of the data. If the graph is not viewable (for example, if there are authorization restrictions set against the graph), it displays Access Denied.


26.2.2 What Happens When You Use the Data Controls Panel to Create a Graph

Dropping a graph from the Data Controls panel has the following effect:

  • Creates the bindings for the graph and adds the bindings to the page definition file

  • Adds the necessary code for the UI components to the JSF page

The data binding XML that JDeveloper generates varies depending on the type of graph you select. The XML represents the physical model of the specific graph type you create. Example 26-1 shows the bindings that JDeveloper generated in the page definition file where a horizontal bar graph was created using data from the ItemsOrdered attribute in the ProductOrdersCount data collection.

Example 26-1 Binding XML for an ADF Bar (Horizontal) Graph

<graph IterBinding="ProductOrdersCountIterator" id="ProductOrdersCount"
       xmlns="http://xmlns.oracle.com/adfm/dvt" type="BAR_HORIZ_CLUST">
  <graphDataMap leafOnly="true">
    <series>
      <data>
        <item value="ItemsOrdered" label="Orders"/>
      </data>
    </series>
    <groups>
      <item value="ProductName" label="ProductName"/>
    </groups>
  </graphDataMap>
</graph>

Example 26-2 shows the code generated for a horizontal bar graph when you drag the ProductOrdersCount data collection onto a JSF page.

Example 26-2 JSF Code for an ADF Bar (Horizontal) Graph

<dvt:horizontalBarGraph id="horizontalBarGraph1"
                        value="#{bindings.ProductOrdersCount.graphModel}"
                        subType="BAR_HORIZ_CLUST">
  <dvt:background>
    <dvt:specialEffects/>
  </dvt:background>
  <dvt:graphPlotArea/>
  <dvt:seriesSet>
    <dvt:series/>
  </dvt:seriesSet>
  <dvt:o1Axis/>
  <dvt:y1Axis/>
  <dvt:legendArea automaticPlacement="AP_NEVER"/>
</dvt:horizontalBarGraph>

26.2.3 What You May Need to Know About Using a Graph's Row Selection Listener for Master-Detail Processing

You can use the row selection listener of a graph (which serves as a master view) to enable clicks on a bar, slice, or other graph data element to update the data in another ADF component (which serves as a detail view). For example, a click on a bar that represents sales for a given product in a graph might cause the display of the detailed sales data related to the product in a pivot table.

The following requirements must be met to achieve this master-detail processing declaratively:

  1. You must use the same data control to provide data for both views as follows:

    1. Bind the graph as a row set to the parent collection in the data control, for example, DepartmentsView.

    2. Bind the other ADF view (such as a table or pivot table) to the dependent detail collection in the data control, for example EmployeesView.

  2. Select Set the current row for master-detail in the Create <type> Graph dialog to automatically set a value for the clickListener attribute of the graph tag and use the processClick method that is already part of the graph binding.

    For example, if the value attribute of the graph tag is value="#{bindings.myGraph.graphModel}", then the clickListener attribute is set to clickListener="#{bindings.myGraph.graphModel.processClick}".

  3. Ensure that the partialTriggers attribute on the parent tag for the detail component is set correctly. It should be set to the ID of the graph component.

You do not have to write Java code for handling clicks on data elements in the graph. The processClick event on the graph binding recognizes click events on data component in a graph and performs the necessary processing.

26.2.4 How to Create a Databound Sparkchart

Sparkcharts are simple, condensed graphs that display trends or variations, often in the column of a table, or inline with text. Line, bar, and area sparkcharts require a single series of data values. Figure 26-6 shows an example of a line sparkchart in a table column.

Figure 26-6 Line Sparkchart

Line sparkchart

Floating bar sparkcharts require two series of data values, one for the float offset, and one for the bar value. Figure 26-7 shows an example of a floating bar sparkchart.

Figure 26-7 Floating Bar Sparkchart

Floating bar sparkchart

You create a sparkchart by inserting the component from the Component Palette and binding the sparkchart to data afterwards. Inserting a sparkchart from the Data Controls panel is not supported. Figure 26-8 shows the Component Gallery that displays when you drag a sparkchart component onto your page from the Component Palette.

Figure 26-8 Create Sparkchart Component Gallery

Create sparkchart component gallery.

You can provide data to sparkcharts in any of the following ways:

  • Specify data statically in child dvt:sparkItem tags. Example 26-3 shows an example of providing static data to a sparkchart.

    Example 26-3 Static Data in Sparkchart

    <dvt:sparkChart>
      <dvt:sparkItem value="20"/>
      <dvt:sparkItem value="15"/>
      <dvt:sparkItem value="30"/>
    </dvt:sparkChart>
    
  • Specify data using EL Expression in child dvt:sparkItem tags. Example 26-4 shows an example of providing data using EL Expressions.

    Example 26-4 EL Expression Data in Sparkchart

    <af:table value="#{sample.tableModel}" var="row">
      <af:column>
        <dvt:sparkChart>
          <dvt:sparkItem value="#{row.col1}"/>
          <dvt:sparkItem value="#{row.col2}"/>
          <dvt:sparkItem value="#{row.col3}"/>
        </dvt:sparkChart>
      </af:column>
    </af:table>
    
  • Specify data using a child accessor in a table. Example 26-5 shows an example of using af:iterator to provide sparkchart data from the data collection model, row.stockValues.

    Example 26-5 Sparkchart Data in Table Child Accessor

    <af:table value="#{sample.tableModel}" var="row">
      <af:column>
        <dvt:sparkChart>
          <af:iterator value="#{row.stockValues}" var="data">
             <dvt:sparkItem value="#{data.closeValue}"/>
          </af:iterator>
        </dvt:sparkChart>
      </af:column>
    </af:table>
    

26.3 Creating Databound Gauges

A gauge plots one data point with indication of whether the data point falls in an acceptable or unacceptable range. One databound gauge component can create a single gauge or an entire set of gauges, depending on the number of rows in the data collection used. In a collection, each row contains the values for a single gauge.

The Component Gallery for gauges allows you to choose from the following categories of gauges:

Each of these categories contains a number of different types of gauge. Explore the Component Gallery that appears when you create a gauge to view all available gauge and category types, and descriptions for each one. Figure 26-9 shows the Component Gallery that appears for ADF gauges.

Figure 26-9 ADF Gauges Component Gallery

ADF Gauges Component Gallery

The data binding process is essentially the same regardless of which type of gauge you create. Only the metric value (that is, the measurement that the gauge is to indicate) is required. However, if a row in a data collection contains range information such as maximum, minimum, and thresholds, then these values can be bound to the gauge to provide dynamic settings. If information that you want to use in a gauge's upper or lower labels is available in the data collection, then you can bind these values to the gauge also.

For information about customizing a gauge after the data binding is completed, see the "Using ADF Gauge Components" chapter in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

26.3.1 How to Create a Databound Dial Gauge

You can use the ADF gauge component to create a dial gauge against a background that specifies ranges of values (also called thresholds) that vary from poor to excellent. The gauge indicator specifies the current value of the metric while the graphic allows you to evaluate the status of that value easily.

Figure 26-10 shows a single dial gauge that appears if you create a gauge from the collection that stores WarrantyPeriodMonths data. Because only one gauge appears, this data collection must contain only a single row of data. The value of the metric (which is 6) appears in a label below the gauge. The range of values in the gauge is displayed as 0 to 24. Threshold ranges are identified at 8, 16, and 24 and are filled with the colors red for poor (below 8), yellow for adequate (from 8 to 16), and green for superior (above 16).

Figure 26-10 The Warranty in Months Dial Gauge

Warranty in months dial gauge

To create a dial gauge using a data control, you bind the gauge component to a collection. JDeveloper allows you to do this declaratively by dragging and dropping a collection from the Data Controls panel.

To create a databound dial gauge:

  1. From the Data Controls panel, select a collection.

    For example, to create a dial gauge in the StoreFrontModule application to display the current warranty period in months for a product in a particular warehouse, you would select the WarehouseStockLevels collection. Figure 26-11 shows the WarehouseStockLevels collection in the Data Controls panel.

    Figure 26-11 Data Collection with Warranty Period for a Product

    Data collection with warranty period for a product
  2. Drag the collection onto a JSF page and, from the context menu, choose Gauges.

  3. In the Component Gallery dialog, choose the category, type of gauge, and quick start layout, and then click OK.

  4. In the Configuration tab of the dialog, do the following:

    • In the Metric box, select the column in your data collection that contains the actual value that the gauge is to plot. This is the only required value in the dialog.

    • In the Minimum box, if your data collection stores a minimum value for the gauge range, select the column that contains this value.

    • In the Maximum box, if your data collection stores a maximum value for the gauge range, select the column that contains this value.

    • In the Top Label box, if your data collection stores a value that you want to display in the top label of the gauge, select the column that contains this value.

    • In the Bottom Label box, if your data collection stores a value that you want to display in the bottom label of the gauge, then select the column that contains this value.

    • In the Threshold Attributes list, if you want to specify threshold values, click the Add icon to insert a row for each threshold and specify the value in that row. Do not create a threshold equal to the maximum value for the gauge because the gauge automatically treats the maximum value as a threshold setting.

  5. Optionally, click the Preview tab to display a live preview of the gauge and its data. If necessary, go back to the Configuration tab so that you can adjust the gauge specifications.

  6. Click OK.

Figure 26-12 shows the completed Create Dial Gauge dialog that generates a dial gauge using the WarehouseStockLevels data collection.


Note:

Only the metric data value is required. Other data values in the dialog are optional and can be specified in the gauge tag through the Property Inspector.


Figure 26-12 Create Dial Gauge Dialog

Create Dial Gauge dialog

In the Property Inspector, after you complete the binding of the gauge, you can set values for additional attributes in the gauge tag and its child tags to customize the component.

26.3.2 What Happens When You Create a Dial Gauge from a Data Control

Dropping a gauge from the Data Controls panel has the following effect:

  • Creates the bindings for the gauge and adds the bindings to the page definition file

  • Adds the necessary code for the UI components to the JSF page

Example 26-6 shows the bindings that JDeveloper generated for the dial gauge that displays warranty in months for a product in a warehouse. This code example shows that the gauge metric receives its value dynamically from the WarrantyPeriodMonths column in the data collection and that the remaining data values have static settings.

Example 26-6 Bindings for a Dial Gauge

<gauge IterBinding="WarehouseStockLevelsIterator" id="WarehouseStockLevels"
       xmlns="http://xmlns.oracle.com/adfm/dvt"
       type="DIAL">
  <gaugeDataMap>
    <thresholds>
      <item value="8" valueType="literal"/>
      <item value="16" valueType="literal"/>
    </thresholds>
    <item type="metric" value="WarrantyPeriodMonths"/>
    <item type="minimum" value="0" valueType="literal"/>
    <item type="maximum" value="24" valueType="literal"/>
    <item type="topLabel" value="Warranty" valueType="literal"/>
    <item type="bottomLabel" value="Months" valueType="literal"/>
  </gaugeDataMap>
</gauge>

Example 26-7 shows the code that ­JDeveloper generated in the JSF page for a dial gauge. The <dvt:thresholdSet> element specifies one <dvt:threshold> element for each threshold. Colors for the threshold ranges default to red, yellow, and green as specified by the values for the fillColor attributes. The <dvt:indicator> element specifies IT_NEEDLE as the indicator to use. This renders a needle at runtime. The default value for <dvt:indicator> renders a line (IT_LINE).

Example 26-7 Code on the JSF Page for an ADF Dial Gauge

<dvt:gauge id="gauge1"
           value="#{bindings.WarehouseStockLevels.gaugeModel}"
           gaugeType="DIAL">
  <dvt:gaugeBackground>
    <dvt:specialEffects/>
  </dvt:gaugeBackground>
  <dvt:thresholdSet>
    <dvt:threshold text="Low" fillColor="#d62800"/>
    <dvt:threshold text="Medium" fillColor="#ffcf21"/>
    <dvt:threshold text="High" fillColor="#84ae31"/>
  </dvt:thresholdSet>
  <dvt:gaugeFrame/>
  <dvt:indicator type="IT_NEEDLE"/>
  <dvt:indicatorBase/>
  <dvt:gaugePlotArea/>
  <dvt:tickLabel/>
  <dvt:tickMark/>
  <dvt:topLabel/>
  <dvt:bottomLabel text="Months"/>
  <dvt:metricLabel position="LP_WITH_BOTTOM_LABEL"/>
</dvt:gauge>

26.3.3 How to Create a Databound Status Meter Gauge Set

You can use the ADF gauge component to create a status meter gauge where the inner rectangle shows the current level of a measurement against the ranges marked in the outer rectangle. The graphic of the status meter gauge allows you to evaluate the condition or progress of a measurement easily.

Figure 26-13 shows a set of status meter gauges that represent the inventory levels in a number of warehouses. This set of gauges results from binding one gauge component to a data collection (WarehouseStockLevels). This data collection contains a row of data for each warehouse. Each row produces one gauge in the set. Notice that all gauges in the set share the same range values of minimum (0) and maximum (1500) with thresholds set at 500 and 1000 and 1500. Each gauge in the set displays the name of the warehouse that it represents and the stock metric for that warehouse in its bottom label.

Figure 26-13 The Warehouse Inventory Status Meter Gauge Set

Wharehouse inventory status meter gauge set

To create a status meter gauge set using a data control, you bind the gauge component to a data collection that contains multiple rows of data. JDeveloper allows you to do this declaratively by dragging and dropping a collection from the Data Controls panel.

To create a databound status meter gauge:

  1. From the Data Controls panel, select a collection.

    For example, to create a status meter gauge in the StoreFrontModule application that displays the quantity of stock on hand in a warehouse, you select the WarehouseStockLevels collection.

  2. Drag the collection onto a JSF page and, from the context menu, choose Gauges.

  3. In the Component Gallery, choose the following:

    • Status Meter or Status Meter (Vertical) in the Categories list

    • The type of gauge that you want to create

    • The quick start layout for the gauge at runtime

  4. Click OK.

  5. In the Create Gauge dialog that appears, select values as described in the following list:

    • Select an attribute binding from the Metric dropdown list. This attribute binding contains the actual value that the gauge is to plot.

    • Input a minimum value in the Minimum field if your data collection stores a minimum value for the gauge range.

    • Input a maximum value in the Maximum field if your data collection stores a maximum value for the gauge range.

    • Write or select a value in the Top Label field if you want to display a label on top of the gauge at runtime.

    • Write or select a value in the Bottom Label field if you want to display a label below the gauge at runtime.

    • Click the Add icon to insert a row for each threshold and specify the value for that threshold if you want to specify threshold values in the Threshold Attributes list. Do not create a threshold equal to the maximum value for the gauge because the gauge automatically treats the maximum value as a threshold setting.


      Note:

      If you selected a quick start layout that includes thresholds, the dialog includes the threshold attributes, and you do not need to insert the threshold rows unless you want to add an additional row to the threshold list.


  6. Optionally, click the Preview tab to display a live preview of the gauge and its data. If necessary, click the Configuration tab so that you can adjust the gauge specifications.

    Figure 26-14 shows the settings for the set of status meter gauges that appears in Figure 26-13. In addition to setting values for the required metric value, this dialog sets values for thresholds and for the name of the warehouse to appear in the gauge's bottom label.

    Figure 26-14 Create Gauge Dialog for Warehouse Inventory Gauge Set

    Gauge binding dialog for warehouse inventory
  7. Click OK.

In the Property Inspector, after you complete the binding of the gauge, you can set values for additional attributes in the gauge tag and its child tags to customize the component as needed.

26.3.4 What Happens When You Create a Status Meter Gauge from a Data Control

Dropping a gauge from the Data Controls panel has the following effect:

  • Creates the bindings for the gauge and adds the bindings to the page definition file

  • Adds the necessary code for the UI components to the JSF page

Example 26-8 shows the row set bindings that were generated for the status meter gauge set that displays inventory levels for each warehouse as illustrated in Figure 26-14. This example shows the value binding created between the gauge metric attribute and the QuantityOnHand value in the data collection. It also shows the value binding between the Bottom Label attribute and the WarehouseName value in the data collection.

Example 26-8 Bindings Code for the ADF Status Meter Gauge Set

<gauge IterBinding="WarehouseStockLevelsIterator" id="WarehouseStockLevels"
       xmlns="http://xmlns.oracle.com/adfm/dvt">
  <gaugeDataMap>
    <thresholds>
      <item value="500" valueType="literal"/>
      <item value="1000" valueType="literal"/>
    </thresholds>
    <item type="metric" value="QuantityOnHand"/>
    <item type="minimum" value="0" valueType="literal"/>
    <item type="maximum" value="1500" valueType="literal"/>
    <item type="bottomLabel" value="WarehouseName"/>
  </gaugeDataMap>
</gauge>

Example 26-9 shows the code generated on the JSF page for the status meter gauge set that shows inventory levels for warehouses. The gaugeSetColumnCount attribute specifies that gauges should be displayed in two columns. The code also specifies three thresholds: Low, Medium, and High. For brevity, the value of the inlineStyle attribute has been omitted.

Example 26-9 Code on the JSF Page for the ADF Status Meter Gauge Set

<dvt:gauge id="gauge1"
           value="#{bindings.WarehouseStockLevels.gaugeModel}"
           gaugeType="STATUSMETER" gaugeSetDirection="GSD_DOWN"
           gaugeSetColumnCount="2">
  <dvt:gaugeBackground>
    <dvt:specialEffects/>
  </dvt:gaugeBackground>
  <dvt:thresholdSet>
    <dvt:threshold text="Low" fillColor="#d62800"/>
    <dvt:threshold text="Medium" fillColor="#ffcf21"/>
    <dvt:threshold text="High" fillColor="#84ae31"/>
  </dvt:thresholdSet>
  <dvt:indicatorBar/>
  <dvt:gaugePlotArea/>
  <dvt:tickLabel/>
  <dvt:tickMark/>
  <dvt:topLabel position="LP_NONE"/>
  <dvt:bottomLabel/>
  <dvt:metricLabel position="LP_WITH_BOTTOM_LABEL"/>
</dvt:gauge>

26.4 Creating Databound Pivot Tables

The ADF pivot table displays a grid of data with rows and columns and optionally, a pivot filter bar to filter data not displayed in the rows or columns. The pivot table has the following structure:

Figure 26-15 shows a Sales pivot table that displays data values for sales and units in the data body, a geography data layer on the column edge, and year and product data layers on the row edge. A pivot filter bar displays a channel filter on the page edge.

Figure 26-15 Sales Pivot Table

Sales pivot table by year and product.

The pivot table aggregates data based on a CSV file of data shown in Figure 26-16.

Figure 26-16 Pivot Table CSV Data

CSV file of data

A Create Pivot Table wizard provides declarative support for data-binding and configuring the pivot table. In the wizard pages you can:

As you lay out the pivot table in the first page of the wizard, corresponding entries are initialized in the following wizard pages. You can use the Back and Next buttons to adjust the pivot table as you go through the wizard pages. You can also skip configuration options in later wizard pages by clicking Finish.

For information about customizing a pivot table after data binding is completed, see the "Using ADF Pivot Table Components" chapter in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

26.4.1 How to Create a Pivot Table

To create a pivot table using a data control, you bind the pivot table component to a collection. JDeveloper allows you to do this declaratively by dragging and dropping a collection from the Data Controls panel.


Tip:

You can also create a pivot table by dragging a pivot table component from the Component Palette. This approach allows you the option of designing the pivot table user interface before binding the component to data.


To demonstrate the creation of the sample Sales pivot table shown in Figure 26-15, a placeholder data control was created and data types defined for the CSV file shown in Figure 26-16. For more information, see Section 29.4, "Using Placeholder Data Controls."

To create a databound pivot table:

  1. From the Data Controls panel, select a collection.

    For example, to create a pivot table that displays sales and units sold by year for each product, you could select the ptExampleData defined for the ptExamplePlaceholder collection in the Data Controls panel, as shown in Figure 26-17.

    Figure 26-17 Data Collection for Product Sales by Year

    Data collection for product sales by year.
  2. Drag the data collection onto a JSF page and, from the context menu, choose Tables > ADF Pivot Table.

  3. In the Select Display Attributes page of the Create Pivot Table wizard, specify the initial layout of the pivot table by doing the following:

    1. If you want to associate a pivot filter bar with your pivot table, select Create Pivot Filter Bar. Optionally, you can drag attributes from the Available Attributes list to the page edge to configure the initial display of filters; otherwise, an empty pivot filter bar is created. If you add a pivot filter bar to a pivot table after data binding, you must edit the page source directly to bind the data model to the pivot filter bar.


      Note:

      You can add attributes to the page edge without creating a pivot filter bar. The attributes are then available for access programmatically in the data model.


    2. For the initial layout, select the attributes for the pivot table's columns, rows, and data body by dragging the attributes from the Available Attributes list to the pivot table layout.

      In the pivot table layout, Data Labels refers to a layer of the pivot table that identifies the data in the cells (data values), and that appears as header labels in the row, column, or page edge. Labels for attributes that you drag to the data body of the pivot table appear in the data labels layer.

      You can drag data labels to any location on the row, column, or page edge. You can also drag attributes to different locations on the same edge or on another edge.

      As an alternative to using a drag operation to place or move attributes in the layout, you can right-click the attribute or use Shift+F10 to display a context menu of options. Figure 26-18 shows the context menu options for the Geography attribute.

      Figure 26-18 Display Attributes Context Menu

      Display attributes context menu.

      Note:

      Potential drill paths between attributes are defined as you lay out multiple attributes on the row, column, and page edges. These drill paths can later be enabled to support pivot table drilling at runtime.


    3. If you want to change from the default selection of Typed Attributes to Name-Value Pairs to configure how data points are stored in a collection, then click the Change Data Shape button. A dialog appears that presents you with the following options:

      • Typed Attributes

        Each kind of data point in the collection is represented by a different attribute. This option is also valid when there is only a single kind of data point in the pivot table.

        For example, if you have data points for Estimated Value and Actual Value, then select Typed Attributes only if you have one attribute for the estimated value and a second attribute for the actual value.

      • Name-Value Pairs

        Indicates that there are multiple kinds of data points, but only a single attribute to designate these types. In this case, the single attribute has -values that identify each kind of data type.

        For example, the attribute might have the value EST for a data point that represents an estimated value and ACT for a data point that represents an actual value.

    For example, to specify the initial layout of the Sales pivot table shown in Figure 26-15, you would drag the Channel attribute to the page edge, Year and Product attributes to the row edge, Sales and Units attributes to the data body (Data Labels), Geography to the column edge, and select Create Pivot Filter Bar, as shown in Figure 26-19.

    Figure 26-19 Select Display Attributes Page of Create Pivot Table Wizard

    Select display attributes page of wizard.
  4. If you want to specify alternative labels or values for the attributes laid out in the Select Display Attributes page of the wizard, use the Specify Attribute Labels page to do the following:

    1. To specify alternative labels for data values in the Data Values area, change the default <Use Data Attribute Name> text label stamped in the header cell for the attribute at runtime. You can enter the text directly or select <No Label> to suppress the header cell, for example, in the case of using a single data value for the pivot table.

    2. To specify alternative labels for attribute categories in the Categories area, change the default <Use Data Attribute Name> text label stamped in the header cell for the attribute at runtime by entering the text directly in the Attribute Display Name column. The label displays in the pivot handle at runtime.

      You can also specify an alternative value for an attribute category by selecting a different attribute in the Attribute Display Value column. For example, you might use a ProductId attribute in the data collection to lay out the pivot table, but you want the ProductName attribute value to improve human readability in the pivot table.

    For example, to specify an alternate label for the Year attribute of the Sales pivot table shown in Figure 26-15, you would enter text (Time) in the Attribute Display Name field, as shown in Figure 26-20.

    Figure 26-20 Specify Attribute Labels Page of Create Pivot Table Wizard

    Specify Attributes Labels page of the wizard.
  5. If you want to expose drill operations in the pivot table at runtime, use the Configure Drilling page of the Create Pivot Table wizard to enable one of the following options:

    • Select Insert Drilling to provide a collapsed or expanded view of the relationship between two attributes while preserving the aggregate value of the details in the data layer. At runtime, a drill icon is displayed in the parent attribute display label.

      Use Insert Parent Row to specify whether the aggregate total for the parent attribute will be displayed before or after the child attributes in the expanded view.

      To enable insert drilling you must also:

      • Select the drill paths to enable. Drill paths are configured based upon the layout of the attributes in the Select Display Attributes page of the wizard.

      • Configure aggregation in the Configure Aggregation page of the wizard.

      For example, Figure 26-21 shows a pivot table using insert drilling to expand the view for the Year data layer. The aggregated value of Sales (52,500 in 2007, 544,150 in 2006) and Units (410 in 2007, 507 in 2006) for each year is displayed in the row above the products.

      Figure 26-21 Pivot Table with Insert Drilling Enabled

      Pivot table with insert drilling expanded.
    • Select Filter Drilling to provide a collapsed or expanded view of the relationships between attributes without preserving the aggregate value of the details in the data layer in the collapsed view. At runtime, a drill icon is enabled in the parent attribute display label.

      Filter drilling focuses the view on the details of the data layer attribute. For example, Figure 26-22 shows a pivot table using filter drilling to expand the view of the Year (2007) data layer, displaying the total Sales (52,500) and Units (410).

      Figure 26-22 Pivot Table with Filter Drilling Enabled

      Pivot table with filter drilling expanded.

      To enable filter drilling you must select the drill paths to enable. Drill paths are configured based upon the layout of the attributes in the Select Display Attributes page of the wizard.

    For example, to enable the insert drilling for the Sales pivot table shown in Figure 26-15, complete the Configure Drilling page of the wizard, as shown in Figure 26-23.

    Figure 26-23 Configure Drilling Page of Create Pivot Table Wizard

    Configure drilling page of the create pivot table wizard.
  6. If you want to define how data is aggregated in totals and subtotals for the pivot table, use one or both of the Configure Aggregation pages of the Create Pivot Table wizard.

    By default, if the attributes displayed in the pivot table do not uniquely identify each row in the data collection, the data from duplicate rows is aggregated to collapse that data into a single pivot table cell. You can also override the default aggregate type for a particular data item.

    • If you want to specify how data is aggregated in the pivot table, in the Data Aggregation page, do the following:

      • If you want to change the default aggregation method for handling duplicate rows, use the Default Function dropdown list to specify the value. Valid values are Sum, Average, Count, Maximum, Minimum, Standard Deviation, and Variance.

      • If you want to override the default aggregate type for a specific data value, click the Add icon to insert a row for the available attributes. Then, in the Function column for each attribute, select the mathematical operation that you want to use for the aggregation. Available options are Sum, Average, Count, Maximum, Minimum, Standard Deviation, and Variance. This attribute is useful only when you have multiple data values (such as Sales and Units) bound to your pivot table.

      For example, to override the default aggregation type for the Units data value in the Sales pivot table shown in Figure 26-15, use the Add icon to add the Units attribute and select Average in the Function column in the Data Aggregation page, as shown in Figure 26-24.

      Figure 26-24 Data Aggregation Page of Create Pivot Table Wizard

      Data aggregation page of the create pivot table wizard.
    • You can also define totals and subtotals for attribute categories added to the column, row, or page edges in the pivot table. In the Categories Totals page, use the Add icon to insert each attribute or select Aggregate All to add all available attributes, and do the following:

      • In the Attribute column, select the attribute that you want to total.

      • In the Function column, select the mathematical operation that you want to use for the aggregation. Available options are Sum, Average, Count, Maximum, Minimum, Standard Deviation, and Variance.

      • In the Insert Total column, select the value that indicates where you want the aggregate display to appear relative to the item referenced in the Attribute column. Valid values are: Before, After, or Replace.

      • In the Total Label column, enter the text that you want to use as a label for the aggregation.


      Note:

      The read-only Insert Drill Totals table displays the category totals automatically defined as a consequence of enabling insert drilling on the pivot table.


      For example, to define totals for the Geography and Year data layers in the Sales pivot table shown in Figure 26-15, select Sum in the Function column and After in the Insert Total column, and enter text (Total Geography and Total Year) in the Total Labels column respectively for each attribute in the Categories Totals page, as shown in Figure 26-25.

      In the resulting pivot table at runtime, expanding a particular Year value will automatically preserve the aggregate total computed from its child value based on the layout and configuration of the insert drill option in the previous wizard page.

      Figure 26-25 Categories Totals Page of the Create Pivot Table Wizard

      Category totals page of Create Pivot Talble wizard.
  7. If you want to configure sorting in the pivot table, use one or both of the Configure Sorting pages in the Create Pivot Table wizard.

    By default, a pivot table initially sorts data based on values in the outer row data layer. You can specify sort order on the data layer of any row, column, or page edge, called a category sort. At runtime, when the data layer is pivoted to a different edge, the specified category sort order is honored.

    You cannot specify a category sort of data labels (data values), although you can order the attributes mapped to the data body in the Select Display Attributes page of the wizard. For example, Figure 26-19 shows a pivot table layout with data values for Sales and Units. While you cannot specify a category sort of these measures, you can specify the order in which the values will appear in the data body of the pivot table at runtime, shown in Figure 26-15.

    You can also specify an initial sort order of the data values in the data body when the pivot table is rendered, called a data sort.

    • To configure sorting by category, in the Category Sort page, use the Add icon to add the attribute for each row, column, or page edge you wish to configure, and do the following:

      • In the Sort Attribute column, accept the default <Use Attribute Value> to specify an alphabetical sort based on the actual values in the pivot table header, or customize the sort order by specifying a data label value from the dropdown list. For example, if the underlying query included a rank calculation for ranking products by profitability, you could choose to see products ordered by (ProductRank, Descending).

      • In the Initial Sort Order select the initial direction of the sort. Valid values are ASCENDING or DESCENDING.

      For example, Figure 26-26 shows the Category Sort page of the wizard configured to display the Channel data layer descending on the column edge and the Year data layer ascending on the row edge.

      Figure 26-26 Category Sort Page of Create Pivot Table Wizard

      Category sort page of the Create Pivot Table wizard.

      At runtime, the pivot table displays as shown in Figure 26-27.

      Figure 26-27 Category Sort Example

      Category sort example
    • To configure data sorting, in the Data Sort page, do the following:

      • Select Sort by Columns to specify an initial sort order of the data when the pivot table is rendered.

      • In the Initial Sort Order dropdown list select the initial direction of the sort. Valid values are ASCENDING and DESCENDING.

      • In the Sequence Nulls dropdown list, select First if you want the null values to appear at the beginning of a sort and select Last if you want the null values to appear at the end of the sort.

      • In the Initial Sort Column table, specify a data value in the Value column for the data layer displayed in the Layer Attribute column.

      For example, Figure 26-28 shows the Data Sort page configured to sort the Channel data layer grouped by Year, based upon Units/World/Canoes data values.

      Figure 26-28 Data Sort Page of the Create Pivot Table Wizard

      Dat sort page of the Create Pivot Table wizard.

      At runtime, the pivot table initially renders as shown in Figure 26-29.

      Figure 26-29 Data Sort Example

      Data sort example
  8. In the Preview Your Pivot Table page of the Create Pivot Table wizard, see a live preview of the data that will be displayed in the pivot table. The preview does not require that you compile and run code. If you are not satisfied with the preview, alter the settings in the binding wizard pages and return again to the preview page to verify that your data looks as desired.

    Figure 26-30 shows the Preview Your Pivot Table page of the wizard for the Sales pivot table shown in Figure 26-15.

    Figure 26-30 Live Data Preview of Pivot Table

    Live data preview of pivot table

26.4.2 What Happens When You Use the Data Controls Panel to Create a Pivot Table

Dropping a pivot table from the Data Controls panel has the following effect:

  • Creates the bindings for the pivot table and adds the bindings to the page definition file

  • Adds the necessary code for the UI components to the JSF page

26.4.2.1 Bindings for Pivot Tables

When you create a pivot table from the Data Controls panel, the page definition file is updated with the bindings. Example 26-10 shows the row set bindings that were generated for the pivot table that displays product sales and units sold within geography by year. The pivot table data map contains the following elements:

  • <columns>: Defines each column item

  • <rows>: Defines each row item in the appropriate sequence

  • <pages>: Defines the items to be included in the pivot filter bar

  • <aggregatedItems>: Defines the totals and subtotals of items

  • <hierarchies>: Defines the potential drill paths between two items

  • <sorts>: Defines category sorts and the initial sort order of pivot table data

The default data aggregation method for duplicate rows is specified in the <data> element. For more information about aggregating duplicates, see Section 26.4.3, "What You May Need to Know About Aggregating Attributes in the Pivot Table."

For more information about sorting operations, see Section 26.4.4, "What You May Need to Know About Specifying an Initial Sort for a Pivot Table."

Example 26-10 Binding XML for the ADF Pivot Table

<pivotTable IterBinding="ptExampleDataIterator" id="ptExampleData"
                xmlns="http://xmlns.oracle.com/adfm/dvt"
                ChangeEventPolicy="ppr">
      <pivotTableDataMap>
        <columns>
          <item value="Geography" itemLabel="Location"/>
          <data aggregateDuplicates="true" defaultAggregateType="SUM">
            <item value="Sales"/>
            <item value="Units" aggregateType="AVERAGE"/>
          </data>
        </columns>
        <rows>
          <item value="Year"/>
        </rows>
        <pages>
          <item value="Channel"/>
        </pages>
        <aggregatedItems>
          <item aggregateLocation="AFTER" aggregateType="SUM" value="Geography"
                aggregateLabel="Total Geography"/>
          <item aggregateLocation="AFTER" aggregateType="SUM" value="Year"
                aggregateLabel="Total Across Years"/>
        </aggregatedItems>
        <drills type="INSERT"/>
        <hierarchies>
          <item value="Year" location="BEFORE">
            <child value="Product" label="Product"/>
          </item>
        </hierarchies>
        <sorts>
          <categorySort item="Channel" direction="DESCENDING"/>
          <categorySort item="Year" direction="ASCENDING"/>
          <qdrSliceSort direction="DESCENDING" edge="rows" grouped="true"
                        nullsFirst="true">
            <item name="Geography" value="World"/>
          </qdrSliceSort>
        </sorts>
      </pivotTableDataMap>
    </pivotTable>

26.4.2.2 Code on the JSF Page for a Pivot Table and Pivot Filter Bar

When the pivot table is created using the Data Controls panel, the necessary code is added to the page. Example 26-11 shows the code generated on the JSF page for the sales pivot table and associated pivot filter bar.

Example 26-11 XML Code on a JSF Page for the Pivot Table and Pivot Filter Bar

<dvt:pivotFilterBar id="pivotTable1pivotFilterBar"
                            value="#{bindings.ptExampleData.pivotFilterBarModel}"
                            modelName="pivotTable1Model"/>
<dvt:pivotTable id="pivotTable1"
                        value="#{bindings.ptExampleData.pivotTableModel}"
                        modelName="pivotTable1Model"/>

26.4.3 What You May Need to Know About Aggregating Attributes in the Pivot Table

If the attributes that you choose to display in your pivot table do not uniquely identify each row in your data collection, then you can aggregate the data from duplicate rows to collapse that data into a single pivot table cell.

For example, if the rows in the data collection shown in Figure 26-15 also contained a store identification, then the data rows from all stores in a given combination of Product, Channel, and Geography would have to be collapsed into a single cell in the pivot table.

The pivot table has the following optional data binding attributes available for controlling the calculation of duplicate data rows:

  • aggregateDuplicates: Boolean property of the <data> element that determines whether special processing is enabled at binding runtime to aggregate data values in duplicate rows. If this attribute is not specified, then false is assumed.

  • defaultAggregateType: String property of the <data> element that specifies a default aggregation method for handling duplicates. Valid values are SUM, AVERAGE, COUNT, MIN, MAX, STDDEV, VARIANCE. If aggregateDuplicates is true and defaultAggregateType is unspecified, then SUM is assumed.

  • aggregateType: String property of an <item> element that enables you to override the default aggregate type for a particular data item. This attribute is useful only when you have multiple data values (such as Sales and Units) bound to your pivot table.

26.4.3.1 Default Aggregation of Duplicate Data Rows

By default, the pivot table uses the SUM operation to aggregate the data values of duplicate data rows in a data collection to produce a single cell value in the pivot table. This means that the aggregateDuplicates attribute is set to true and the defaultAggregateType is assumed to be SUM.

The <data> element shown in Example 26-10 is an example of such default aggregation.

26.4.3.2 Custom Aggregation of Duplicate Rows

If you want the pivot table to use a different mathematical operation to aggregate the data values of duplicate rows, then you set the defaultAggregateType to the desired operation.

Example 26-12 shows a data element with the defaultAggregateType set to SUM. This operation would be appropriate if you want to see the total of sales from all stores for each unique combination of Product, Channel, and State.

Example 26-12 Binding XML for Custom Aggregation of Duplicate Rows

<pivotTable IterBinding="SalesPivotTable1Iterator" id="SalesPivotTable11"
        xmlns="http://xmlns.oracle.com/adfm/dvt">
  <pivotTableDataMap>
    <columns>
       <data aggregateDuplicates="true" defaultAggregateType="SUM">
         <item value="Sales"/>
       </data>
       <item value="Geography"/>
    </columns>
    <rows>
       <item value="Channel"/>
       <item value="Product"/>
    </rows>
    <aggregatedItems>
      <item aggregateLocation="After" aggregateType="AVERAGE" 
          value="Product" aggregateLabel="Average"/>
    </aggregatedItems>
  </pivotTableDataMap>
</pivotTable>

If you have a pivot table with multiple data values (such as sales and the average size of a store in square feet) and you want to sum the sales data values in duplicate rows, but you want to average the square feet data values, then do the following:

  • On the <data> element, set the defaultAggregateType to SUM.

  • On the <item> element for the square feet attribute, set the aggregateType to AVERAGE.

Example 26-13 shows the <columns> elements wrapped by a PivotTableDataMap element. The <data> element contains the default attributes for aggregation. These apply to all data items that do not have a specific custom aggregateType attribute specified.

Example 26-13 Data and Item Elements for Multiple Custom Aggregations

    <columns>
       <data aggregateDuplicates="true" defaultAggregateType="SUM">
         <item value="Sales" label="Total Sales"/>
         <item value="StoreSqFeet" label="Avg Sq Feet" aggregateType="AVERAGE"/>
       </data>
       <item value="State"/>
    </columns>

26.4.4 What You May Need to Know About Specifying an Initial Sort for a Pivot Table

By default, a pivot table initially sorts data based on values in the outer row data layer. You can specify sort order on the data layer of any row, column, or page item, called a category sort. At runtime, when the data layer is pivoted to a different edge, the specified category sort order is honored. Insert a categorySort element inside the sorts element and set values for the attributes as described in Table 26-2.

Table 26-2 Attribute Values for categorySort Element

AttributeDescription

item

Specify the column, row, or page item for which you are setting the category sort. A value for this attribute is required.

direction

Specify the initial direction of the sort. Valid values are ASCENDING and DESCENDING. A value for this attribute is required.


You can also specify the initial sort order of the data values in the data body when the pivot table is rendered, called a data sort. You can change the default behavior by inserting a sorts element inside the pivotTableDataMap element of a pivot table binding in the page definition file. Insert a qdrSliceSort element inside the sorts element and set values for the attributes as described in Table 26-3.

Table 26-3 Attribute Values for qdrSliceSort Element

AttributeDescription

direction

Specify the initial direction of the sort. Valid values are ASCENDING and DESCENDING. A value for this attribute is required.

edge

Specify columns or rows to determine which edge sorts data. A value for this attribute is required.

grouped

Specify true if you want to sort slices within their parent or false if you want to sort across the entire edge. A value for this attribute is optional. The default value is false.

nullsFirst

Specify true if you want null values to appear at the beginning of a sort and false if you want null values to appear at the end of a sort. A value for this attribute is optional.


Insert one or more item tags inside the qdrSliceSort tag. An item tag specifies the slice on the opposite edge from which the values to be sorted should be obtained. Set values for the attributes as described in Table 26-4.

Table 26-4 Attribute Values for item Tag

AttributeDescription

name

Specify the name of the layer to sort on. Typically, this is the column name in the row set. Specify DataLayer if you want to specify the layer that contains the data columns in a row set (for example, Sales, Costs, and so on).

value

Specify the value of the specified layer on the desired slice.


26.5 Creating Databound Geographic Maps

An ADF geographic map is an ADF Data Visualization component that provides the functionality of Oracle Spatial within Oracle ADF. This component allows users to represent business data on a geographic map and to superimpose multiple layers of information (known as themes) on a single map. These layers can be represented as any of the following themes: bar graph, pie graph, color, point, and predefined theme.

Figure 26-31 shows a geographic map component that uses a base map for a region in the United States with the following themes:

Figure 26-31 Geographic Map with Color Theme, Pie Graph Theme, and Point Theme for a Product

Geographic map with color, pie graph, and point themes

A geographic map component differs from other ADF Data Visualization components as you do not need to put multiple maps on a page to display multiple sets of data. This contrasts to components such as graphs where you can put multiple graphs on a page. Instead, you show how multiple sets of data relate to each other spatially or, for a specific point, you display different attributes layered in separate themes.

The geographic map component itself is not bound to data. However, each map theme has its own data bindings.

A base map forms the background on which the ADF geographic map component layers the themes that developers create.

In Oracle Spatial, administrators create base maps that consist of one or more themes. The administrator controls the visibility of the base map themes. When you zoom in and out on a base map, various base map themes are hidden or displayed. At the ADF geographic map component level, you cannot use zoom factor to control the display of the themes created by the administrator on the base map.

When you overlay themes on the ADF geographic map, you can control the visibility of your themes by setting the maxZoom and minZoom attributes of the tags related to these themes. At runtime, you can also hide or display your custom themes by using the View menu of the Map toolbar or by using other ADF components that you create on the page.

For information about customizing a geographic map after data-binding is completed, see the "Using ADF Geographic Map Components" chapter in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

26.5.1 How to Create a Geographic Map with a Point Theme

To create a geographic map, you first configure the map (that is, select a base map and provide URLs for processing) and then bind a theme of the map to a data collection. JDeveloper allows you to do this declaratively by dragging and dropping a collection from the Data Controls panel for the theme that you want to create.

When you create a map point theme, you have the option of customizing the style of the points that appear in the map. For each different point style, you can use a mapPointStyleItem tag.

To create a geographic map with a databound point theme:

  1. From the Data Controls panel, select a collection.

    Figure 26-32 shows an example where you could select the WarehouseStockLevelsByProduct1 collection in the Data Controls panel to create a geographic map with a point theme that displays an image to represent the quantity on hand for each warehouse point.

    Figure 26-32 Data Collection for Warehouse Stock Levels

    Data collection for warehouse stock levels
  2. Drag the collection onto a JSF page and, from the context menu, choose Geographic Map > Map and Point Theme.

  3. If you have not yet configured a map on the page, then in the ensuing Create Geographic Map dialog, click the New icon to display the Create Geographic Map Configuration dialog and do the following:

    1. In the Id field enter the unique identifier for the map configuration.

    2. In the MapViewer URL field enter the URL for the Oracle Application Server MapViewer Service.

    3. In the Geocoder URL field select the URL for the Geocoder Web service that converts street addresses into latitude and longitude coordinates for mapping.


      Note:

      The Geocoder URL is needed only if you do not already have longitude and latitude information for addresses.


    4. Click OK to dismiss the dialog and return to the Create Geographic Map dialog.

  4. In the Maps page, you select the base map for the geographic map component and provide other settings to use with the map by doing the following:

    1. From the Data Source list select the collection of maps from which you will choose a base map.

    2. From the Base Map list select the map that will serve as the background for the geographic map component.

    3. To specify values for the StartingX field and the StartingY field click on the image of the map to center it within the Preview window.

      You can use the arrows in the map navigator in the upper left-hand corner to move the map in the appropriate direction.

    4. Optionally use the sliding arrow in the Preview window to adjust the zoom factor of the map.

    5. Click OK to dismiss the dialog and to display the Create Point Map Theme dialog.

  5. In the Theme Id field enter the unique identifier for the point map theme.

  6. In the Location section, specify whether the point location is to be specified by a pair of x and y coordinates (longitude and latitude) or as an address.

    The choice you select for location will determine which controls appear in the Location section.


    Tip:

    Using x and y coordinates is a more efficient way to present data on the map rather than using the Address controls, which must be converted by a Geocoder to x and y coordinates. If the data collection has more than 100 rows, then to ensure adequate performance, use x and y coordinates.


  7. For the x and y point location, you select the data that corresponds to the following items:

    • X (Longitude): The horizontal location of the point on the map.

    • Y (Latitude): The vertical location of the point on the map.

    • Label: The labels for the points in the top section of the information window, which is displayed when you click a point.

  8. In the Point Data section, provide the following information that identifies the data associated with the point, its label, and optionally the style for the point:

    • In the Data field, select the data column that is associated with the point, such as QuantityOnHand.

    • In the Label field, enter the text that will appear in the information window before the data value when you click a point.

    • Optionally, in the Category field, select a data column to use for finding the appropriate style for a point. If you select a value for Category, that value is stored in the binding for this point theme and then matched against the itemValue attribute of the mapPointStyleItem tags that you create for this point theme.


      Note:

      If your data does not have a column that you want to use as a category for finding the style of a point, you can also use mapPointStyleItem tags to define styles related to data ranges (such as high, medium, and low) that are matched to the values in the column that you select in the Data field. For more information, see Section 26.5.2, "How to Create Point Style Items for a Point Theme".


  9. Select the Enable Row Selection field only if you want to enable the selection of rows in a related component. You select this option when the page contains a component that is linked to a data collection which is related to the geographic map that you are creating.

  10. Click OK.

Figure 26-33 shows the Create Point Map Theme dialog for a geographic map with a point theme that displays an image representing quantity on hand for each warehouse point.

Figure 26-33 Create Point Map Theme Dialog for Warehouse Inventory Levels

Binding dialog for point map theme for warehouse levels

26.5.2 How to Create Point Style Items for a Point Theme

There are a variety of options available for creating point style items for use in a given map point theme. These are:

  • A single image for all data points

  • Separate images for each data point category

  • Images that represent low, medium, and high data value ranges

After you create the data binding for a map point theme, you have the option of selecting a single built-in image that should be used for all points in that map theme. In the Property Inspector, you can make this selection in the builtInImage attribute of the mapPointTheme tag. The default value for this attribute is OrangeBall.

Alternatively, if you specify a value for Category in the Create Point Map Theme dialog, then you should also create a set of point style items to determine a separate image that represents data points in each category. In this case, you do not use the minimum and maximum values in the point style item tags. Instead, you set the itemValue attribute of point style item tags to a value that matches entries in the data column that you specified for Category.

In a point theme for a geographic map, if you do not specify a value for Category, you can still use the mapPointStyleItem child tags of the mapPointTheme tag to specify ranges of values (such as low, medium, and high) and the images that are to represent these ranges. If you do this, then each point will be represented by an image that identifies the range in which the data value for that point falls.

The following procedure assumes that you have already created a geographic map with a point theme.

To add point style items to a map point theme to represent low, medium, and high data value ranges:

  1. In the Structure window, right-click the dvt:mapPointTheme tag and choose Insert inside the dvt:mapPointTheme > Point Style Item.

  2. In the Point Style Item Property Inspector, set values as described Table 26-5, "Properties for Point Style Item".

    Table 26-5 Properties for Point Style Item

    For this propertySet this value

    Id

    Specify a unique ID for the point style item.

    MinValue

    Specify the minimum value in a data range that you define.

    MaxValue

    Specify the maximum value in a data range that you define.

    ShortLabel

    Specify text to appear when a user hovers over the point item. For example, if you define a point item for low inventory, then enter Low Inventory as the value for this property.

    ImageURL

    Specify the URL to the image file or select it from the dropdown list. At runtime, the image you specify appears on the map to represent the data range identified by the MinValue and MaxValue properties.

    Alternatively, you can select one of a number of predefined images referenced by the BuiltInImage dropdown list that appears in the Other section.

    HoverImageURL

    Specify the URL to the image file or select it from the dropdown list. At runtime, the image you specify appears when a user hovers over the point item.

    SelectedImageURL

    Specify the URL to the image file or select it from the dropdown list. At runtime, the image you specify appears when a user selects the point item.


  3. If you defined a data value range for a low data value range in Steps 1 and 2, then repeat Steps 1 and 2 to define medium and high data value ranges with appropriate values.


Note:

The use of mapPointStyleItem child tags to customize the style of points is a declarative approach that lets you provide custom point images. For information about using a callback to provide not only custom images but also custom HTML, see Section 26.5.4, "What You May Need to Know About Adding Custom Point Style Items to a Map Point Theme".


26.5.3 What Happens When You Create a Geographic Map with a Point Theme

Dropping a geographic map and a point theme (which in this case would be the initial theme added to the map) from the Data Controls panel has the following effect:

  • Creates the bindings for the point theme and adds the bindings to the page definition file

  • Adds the necessary tags to the JSF page for the geographic map component

  • Adds the necessary point theme tags to the JSF page within the map XML

26.5.3.1 Binding XML for a Point Theme

Example 26-14 shows the row set bindings that were generated for the point theme of the geographic map.

Example 26-14 Point Theme Binding XML

<mapTheme IterBinding="WarehouseStockLevelsByProduct1Iterator"
     id="WarehouseStockLevelsByProduct1"
     xmlns="http://xmlns.oracle.com/adfm/dvt">
  <mapThemeDataMap mapThemeType="point">
    <item type="data" value="QuantityOnHand" label="Product Quantity"/>
    <item type="lat_long" latitude="Latitude"
      longitude="Longitude" label="WarehouseName"/>
  </mapthemeDataMap>
</mapTheme>

26.5.3.2 XML Code on the JSF Page for a Geographic Map and Point Theme

Example 26-15 shows the XML code generated on the JSF page for the geographic map and its point theme. Notice the code for the three kinds of point style settings based on data value.

The initial point style setting (ps0) applies to values that do not exceed 500. This point style displays an image for very low inventory and provides corresponding tooltip information.

The second point style setting (ps1) applies to values between 500 and 1000. This point style displays an image for low inventory and provides corresponding tooltip information.

The final point style setting (ps2) applies to values between 1000 and 1600. This point style displays an image for high inventory and provides corresponding tooltip information.

Example 26-15 Geographic Map and Point Theme XML Code on the JSF Page

<dvt:map id="map1" 
         mapServerConfigId="mapConfig1"
         inlineStyle="width:850px;height:490px"
         startingX="-96.0"
         baseMapName="ELOCATION_MERCATOR.WORLD_MAP"
         startingY="37.0" zoomBarPosition="WEST"
         showScaleBar="false"
         partialTriggers="go pointTheme pieTheme colorTheme" mapZoom="3">
    <dvt:mapPointTheme id="mapPointTheme1"
                       shortLabel="Warehouse Stock Levels"
                       selectionListener="#{MapBean.processSelection}"
                       value="#{bindings.WarehouseStockLevelsByProduct1.geoMapModel}"
                       rendered="#{AppState.showPointTheme}">
      <dvt:mapPointStyleItem id="ps0"
                             minValue="0"
                             maxValue="500"
                             imageURL="/images/low.png"
                             selectedImageURL="/images/lowSelected.png"
                             shortLabel="Very Low Inventory"/>
      <dvt:mapPointStyleItem id="ps1"
                             minValue="500"
                             maxValue="1000"
                             imageURL="/images/medium.png"
                             selectedImageURL="/images/mediumSelected.png"
                             shortLabel="Low Inventory"/>
      <dvt:mapPointStyleItem id="ps2"
                             minValue="1000"
                             maxValue="1600"
                             imageURL="/images/regularGreen.png"
                             selectedImageURL="/images/regularGreenSelected.png"
                             shortLabel="High Inventory"/>
    </dvt:mapPointTheme>
  </dvt:map>

26.5.4 What You May Need to Know About Adding Custom Point Style Items to a Map Point Theme

If you want to provide custom HTML as well as custom images for map points, then you can use the customPointCallback attribute of the dvt:mapPointTheme tag to accomplish this customization.


Important:

If you set the customPointCallback attribute for a map point theme, the map ignores any dvt:mapPointStyleItem child tags because the callback overrides these tags.


To use a callback to customize the style of map points:

  1. Write a method in Java to perform the desired point customization.

  2. Store this method in a managed bean for the map.

    For more information about managed beans, see the "Creating and Using Managed Beans" section in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

  3. After you finish data-binding the map point theme, use the Property Inspector to specify a reference to the managed bean method in the customPointCallback attribute of the dvt:mapPointTheme tag.

    For example, if the managed bean is named MapSampleBean and the method is named setCustomPointStyle, then the reference becomes #{mapSampleBean.CustomPointStyle}.

26.5.5 How to Add a Databound Color Theme to a Geographic Map

When you create a geographic map, you can choose to create themes (point, color, and graph) in any sequence that you wish.

The following procedure assumes that a geographic map has already been configured and, therefore, the map component does not display the dialog for configuring the map. Instead, only the dialog for creating the color theme appears.

To add a databound color theme to a geographic map:

  1. From the Data Controls panel, select a collection.

    Figure 26-34 shows an example where you could select the ProductPopularity1 collection in the Data Controls panel to create a color map theme that shows product popularity by the color of regions (for example, states).

    Figure 26-34 Data Collection for Product Popularity by State

    Data collection for product popularity by state
  2. Drag the collection onto a JSF page which already contains a geographic map component and, from the context menu, choose Geographic Map > Color Theme.

  3. In the ensuing Create Color Map Theme dialog, enter a unique identifier for the map theme in the Id field.

  4. In the Base Map Theme section, identify the base map color theme to use for the geographic map by doing the following:

    1. In the Name field, select the name of the base map theme.

    2. For Location, select the location column in the data collection that should be matched to the location column in the base map theme that you selected.

    3. Optionally, click View Sample Theme Data to display the Sample Theme Data dialog, in which you can examine the first several rows of the actual data so that you can identify the appropriate location column.

      For example, if you want to view the data for a region that consists of states in the United States map, you might select MAP_STATES_NAME as shown in Figure 26-35.


      Note:

      It is possible for an administrator of Oracle Spatial to disable the display of sample data. If this button is not available, then consult the administrator for guidance.


      Figure 26-35 Sample Theme Data for Regions or States

      Sample theme data for regions or states
  5. In the Appearance section, specify the look of the color theme as follows:

    1. In Data Bucket Count, enter the number of groups for the data in this geographic map. Each group is coded with a color. After specifying this number, you can provide colors for the minimum value and the maximum value. The colors for the other values are chosen automatically using an RGB algorithm.

    2. In Minimum Value Color, select the color for the minimum value.

    3. In Maximum Value Color, select the color for the maximum value.


    Note:

    If you want to specify an exact color for each data bucket, see Section 26.5.7, "What You May Need to Know About Customizing Colors in a Map Color Theme".


  6. In the Data section, provide the following information about the data in the collection:

    1. For Location, select the column in the data collection that should match the values in the location column that you selected from the base map theme.

    2. For Location Label, select the column in the data collection that contains the labels associated with the values in the location column. These labels are shown in the information window that is displayed when you click or hover over a color.

    3. For Data Label, enter the label to use for describing the data in the information window and the tooltip that is displayed when you click or hover over a color. For example, the information window might include a label before the data value, such as Product Popularity.

  7. Use Enable Row Selection only if you want to enable master-detail relationships. This is useful when the data collection for the map theme is a master in a master-detail relationship with a detail view that is displayed in another UI component on the page.

Figure 26-36 shows the Create Color Map Theme dialog for the product popularity by state color theme.

Figure 26-36 Create Color Map Theme for Product Popularity By State

Color map theme binding for product popularity by state

26.5.6 What Happens When You Add a Color Theme to a Geographic Map

Dropping a color theme from the Data Controls panel to an existing geographic map has the following effect:

  • Creates the bindings for the color theme and adds the bindings to the page definition file

  • Adds the necessary color theme tags to the JSF page within the map XML

26.5.6.1 Binding XML for a Color Theme

Example 26-16 shows the row set bindings that were generated for the color theme of the geographic map.

Example 26-16 Color Theme Binding XML

<mapTheme IterBinding="ProductPopularity1Iterator" id="ProductPopularity1"
        xmlns="http://xmlns.oracle.com/adfm/dvt">
   <mapThemeDataMap mapThemeType="color">
      <item type="location" value="StateProvince" label="StateProvince"/>
      <item type="data" value="CountAddressesStateProvince"
           label="Popularity"/>
   </mapThemeDataMap>
</mapTheme>

26.5.6.2 XML Code on the JSF Page for a Color Theme

Example 26-17 shows the XML code generated on the JSF page for a color theme that represents product popularity in different states on the United States map.

Example 26-17 Color Theme XML Code on the JSF Page

<dvt:mapColorTheme id="mapColorTheme1"
     themeName="MAP_STATES_NAME"
     shortLabel="Product Popularity"
     value="#{bindings.ProductPopularity1.geoMapModel}"
     locationColumn="POLYGON_NAME"
     minColor="#ff0000"
     maxColor="#008200"
     bucketCount="5"/>

26.5.7 What You May Need to Know About Customizing Colors in a Map Color Theme

While you are data-binding a map color theme, you can specify only a minimum color and a maximum color for the data buckets. The map uses an algorithm to determine the colors of the buckets between the minimum and maximum. However, after the data-binding is finished, you have the option of specifying the exact color to be used for each data bucket.

In the Object Inspector, for the dvt:mapColorTheme tag you can use the colorList attribute to specify the color for each bucket. You can either bind a color array to this attribute or you can specify a string of colors using a semicolon separator.

For example, if the value of this attributes is set to: #ff0000;#00ff00;#0000ff, then the color of the first bucket is red, the second bucket is green, and the third bucket is blue.

26.5.8 How to Add a Databound Pie Graph Theme to a Geographic Map

When you create a geographic map, you can choose to create themes (point, color, and graph) in any sequence that you wish. However, only one graph theme (pie or bar) can be visible at a time on the ADF geographic map component.

The following procedure assumes that a geographic map has already been configured and, therefore, the map component does not display the dialog for configuring the map. Instead, only the dialog for creating the pie graph theme appears.

To add a databound pie graph theme to a geographic map:

  1. From the Data Controls panel, select a collection.

    Figure 26-37 shows an example where you could select the PopularCategories1 collection to create a pie bar theme in an existing geographic map component to represent the popular product categories within a state.

    Figure 26-37 Data Collection for Popular Product Categories by State

    Data collection for popular product categories by state
  2. Drag the collection onto a JSF page and, from the context menu, choose Create > Pie Graph Theme.

  3. In the ensuing Create Pie Graph Theme Binding dialog, do the following to identify the new theme and the base map theme elements that you want to work with:

    1. For Theme Id, enter a unique identifier for the pie graph theme that you are creating.

    2. In the Base Map Theme section, select the name of the base map and the region in which you want to place the pie graphs.

  4. In the Appearance section, under Data, do the following:

    1. For Location, select the location column in the data collection that should be matched to the location column in the base map theme that you selected.

      If needed, click View Sample Theme Data to examine the first several rows of the actual data so that you can identify the appropriate location column.

    2. For Location Label, select the column in the data collection that contains labels for the locations in the data collection.

    3. In the grid for Series Attributes, enter each attribute that contains values that you want represented in the pie graph that you are creating.

    4. Beside each series attribute, enter text that should be used as a label for the data values in the series attribute.

  5. Select Enable Row Selection only if you want to enable the selection of rows in a related component. You select this component when the page contains a component that is linked to a data collection that is related to the geographic map that you are creating.

  6. Click OK.

Figure 26-38 shows the completed Create Pie Graph Map Theme dialog for the product popularity by state pie graph theme.

Figure 26-38 Create Pie Graph Map Theme for Product Popularity by State

Dialog for pie graph map theme

26.5.9 What Happens When You Add a Pie Graph Theme to a Geographic Map

Dropping a pie graph theme from the Data Controls panel to an existing geographic map has the following effect:

  • Creates the bindings for the pie graph theme and adds the bindings to the page definition file

  • Adds the necessary pie graph theme code to the JSF page within the map XML

26.5.9.1 Binding XML for a Pie Graph Theme

Example 26-18 shows the row set bindings that were generated for the pie graph theme of the geographic map.

Example 26-18 Pie Graph Theme Binding XML

<mapTheme IterBinding="PopularCategoriesByState1Iterator"       
        id="PopularCategoriesByState1"
        xmlns="http://xmlns.oracle.com/adfm/dvt">
   <mapThemeDataMap mapThemeType="pieChart">
       <item type="location" value="StateProvince" label="StateProvince"/>
       <item type="data" value="AudioVideo" label="Audio Video"/>
       <item type="data" value="CellPhones" label="Cell Phones"/>
       <item type="data" value="Games" label="Games"/>
   </mapThemeDataMap>
</mapTheme>

26.5.9.2 Code on the JSF Page for a Pie Graph Theme

Example 26-19 shows the XML code generated on the JSF page for the pie graph theme of the geographic map.

Example 26-19 Pie Graph Theme Code on the JSF Page

<dvt:mapPieGraphTheme id="mapPieGraphTheme1"
     themeName="MAP_STATES_NAME"
     shortLabel="Popular Categories"
     pieRadius="10"
     styleName="comet"
     value="#{bindings.PopularCategoriesByState1.geoMapModel}"
     locationColumn="POLYGON_ID"/>

26.6 Creating Databound Gantt Charts

A Gantt chart is a type of bar graph (with time on the horizontal axis). It is used in planning and tracking projects to show tasks or resources in a time frame with a distinct beginning and end.

When you create a Gantt chart, you can choose from the following types:

For information about customizing Gantt chart charts after data-binding is completed, see the "Using ADF Gantt Chart Components" chapter in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

26.6.1 How to Create a Databound Project Gantt Chart

For a project Gantt chart, you must specify values for tasks. Optionally, you can specify values for split tasks, subtasks, recurring tasks, and dependencies between tasks, if your data collection has accessors for this additional information.

The project Gantt chart is displayed with default values for overall start time and end time and for the major and minor time axis values. In a project Gantt chart, the setting for the major time axis defaults to weeks and the setting for the minor time axis defaults to days.

Figure 26-39 shows a project Gantt chart in which each task is an order to be filled. The list region on the left side of the splitter shows columns with the name of the person who is responsible for the order and columns for the order date and shipped date. In the chart region on the right side of the splitter, the Gantt chart displays a horizontal bar from the order date to the ship date for each order.

Figure 26-39 The Order Shipping Project Gantt Chart

Display of the order shipping project gantt

To create a project Gantt chart using a data control, you bind the project Gantt chart component to a data collection. JDeveloper allows you to do this declaratively by dragging and dropping a collection from the Data Controls panel.


Tip:

You can also create a project Gantt chart by dragging a project Gantt chart component from the Component Palette and completing the Create Project Gantt dialog. This approach allows you to design the Gantt chart user interface before binding the component to data.


To create a databound project Gantt chart:

  1. From the Data Controls panel, select a data collection. For a Gantt chart, you can select a row set collection (which produces a flat list of tasks) or a basic tree collection (which produces a hierarchical list of tasks).

    Figure 26-40 shows an example where you could select the OrderShippingSummary1 collection in the Data Controls panel to create a project Gantt chart that displays the progress of order shipping.

    Figure 26-40 Data Collection for Shipping Orders

    Data collection for shipping orders
  2. Drag the collection onto a JSF page and, from the context menu, choose Gantt > Project.

  3. In the ensuing Create Project Gantt dialog, you do the following to connect task-related controls in the pages at the top of the dialog with corresponding columns in the data collection:

    1. In the Tasks page at the top of the dialog, you select the columns in the data collection that correspond to each of the following controls: Task Id, Start Time, and End Time. By clicking Show More in the dialog, you can select additional columns in the data collection that correspond to the following controls: Actual Start, Actual End, % Complete, Completed Through, Critical, and Is Container.

      Optionally, you can select a column in the data collection to map to the task type. If you do not bind Task Type to a column in your data collection, then all tasks default to Normal. The task type controls the appearance of the task bar when it is rendered in the Gantt chart.

      A project Gantt chart component supports the following task types that you configure the data collection to return: Summary, Normal, and Milestone.

    2. If the data collection has an accessor for subtasks, you have the option of using the Subtasks page in the dialog to select the subtasks accessor and to select the columns in the data collection that correspond to each of the following controls: SubTask Id, Start Time, and End Time. Optionally, you can select a column in the data collection to map to the subtask type. If you do not bind SubTask Type to data, then all subtasks default to Normal.

      A project Gantt chart component supports the following task types that you configure the data collection to return: Summary, Normal, and Milestone.

      If you do not bind subtasks, then the Gantt chart cannot render a hierarchy view of tasks. If you bind subtasks, then you can drill from tasks to subtasks in the hierarchy view of the Gantt chart.

    3. If the data collection has an accessor for dependent tasks, you have the option of using the Dependent Tasks page in the dialog to select the dependent task accessor and to select the columns in the data collection that correspond to the following controls: Dependency Type, From Task Id, and To Task Id.

      Dependent tasks are linked by their dependency between their finish and start times.

      A project Gantt chart component supports the following dependency types that you configure the data collection to return: fs (for finish to start), ss (for start to start), ff (for finish to finish), and sf (for start to finish).

    4. If the data collection has an accessor for split tasks, you have the option of using the Split Tasks page in the dialog to select Split Tasks accessor and to select the columns in that data collection that correspond to each of the following controls: SplitTask Id, Start Time, and End Time.

    5. If the data collection has an accessor for recurring tasks, you have the option of using the Recurring Tasks page in the dialog to select the recurring tasks accessor and to select the columns in that data collection that correspond to each of the following controls: Recurring Task Id, Type, Start Time, and End Time.

    6. You can use the Appearance page in the dialog to specify the attributes that correspond to the Label of the task bar, and up to three icons to associate with the task bar.

  4. In the Table Columns section, you specify the columns to appear in the list region of the Gantt chart. Specify one row of information for each column that is to appear. Use the New icon to add new rows. Use the arrow icons to arrange the rows in the exact sequence that you want the columns to appear in the Gantt chart list.


    Note:

    The first row that you specify in the Table Columns section designates the nodestamp column for the list region. The nodestamp column is the one that you can expand or collapse when you have a subtask collection.


    For each row, you provide the following specifications:

    • Display Label: Select the values for the headers of the columns in the Gantt chart list. If you select <default>, then the text for the header is automatically retrieved from the data binding.

    • Value Binding: Select the columns in the data collection to use for the columns in the Gantt chart list. The available values are the same as those for the tasks group.

    • Component to Use: Select the type of component to display in the cell of the Gantt chart list. The default is the ADF Output Text component.

  5. Click OK.

  6. If you want to include a legend in the Gantt chart, right-click the project Gantt chart node in the Structure window and choose Insert inside dvt:projectGantt > Legend.

    The legend shows information about each symbol and color coded bar that is used to represent different task types. It also shows detailed information about the task that is selected in the Gantt chart.

Figure 26-41 shows the dialog used to create the project Gantt dialog from the data collection for shipping orders.

Figure 26-41 Create Project Gantt Dialog for Orders Shipped

This diagram is described in surrounding text.

After completing the data binding dialog, you can use the Property Inspector to specify values for additional attributes for the project Gantt chart.

26.6.2 What Happens When You Create a Project Gantt Chart from a Data Control

Dropping a project Gantt chart from the Data Controls panel has the following effect:

  • Creates the bindings for the Gantt chart and adds the bindings to the page definition file

  • Adds the necessary code for the UI components to the JSF page

Example 26-20 displays the row set bindings that were generated for the project Gantt chart that displays orders shipped. This code example shows that there are nodes defined for tasks and subtasks, along with attributes. There are also nodes defined for dependent tasks, split tasks, and recurring tasks but no attributes.

Example 26-20 Bindings for a Project Gantt Chart

<gantt IterBinding="OrderShippingSummary2Iterator"
   id="OrderShippingSummary2" xmlns="http://xmlns.oracle.com/adfm/dvt">
<ganttDataMap>
<nodeDefinition DefName="oracle.fod.model.OrderShippingSummary"
                type="Tasks">
  <AttrNames>
    <Item Value="PersonId" type="taskId"/>
    <Item Value="OrderDate" type="startTime"/>
    <Item Value="TaskType" type="taskType"/>
    <Item Value="ShippedDate" type="endTime"/>
  </AttrNames>
  <Accessors>
    <Item Value="OrderShippingDetails" type="subTasks"/>
  </Accessors>
</nodeDefinition>
<nodeDefinition type="SubTasks"
                DefName="oracle.fod.model.OrderShippingDetails">
  <AttrNames>
    <Item Value="OrderId" type="taskId"/>
    <Item Value="OrderDate" type="startTime"/>
    <Item Value="TaskType" type="subTaskType"/>
    <Item Value="ShippedDate" type="endTime"/>
  </AttrNames>
</nodeDefinition>
<nodeDefinition type="Dependents">
  <AttrNames/>
</nodeDefinition>
<nodeDefinition type="SplitTasks">
  <AttrNames/>
</nodeDefinition>
<nodeDefinition type="RecurringTasks">
  <AttrNames/>
</nodeDefinition>
</ganttDataMap>
</gantt>

Example 26-21 shows the code generated on the JSF page for the ADF project Gantt chart. This tag code contains settings for the overall start and end time for the project Gantt chart. It also shows the default time axis settings for the major axis (in weeks) and the minor axis (in days). Finally, it lists the specifications for each column that appears in the list region of the Gantt chart. For brevity, the code in the af:column elements for OrderStatusCode and ShippedDate has been omitted.

Example 26-21 Code on the JSF Page for a Project Gantt Chart

<projectGantt id="projectGantt1"
             value="#{bindings.OrderShippingSummary2.projectGanttModel}"
             var="row" startTime="2008-05-17" endTime="2008-07-07"
             inlineStyle="width:100%; height:100%;">
  <f:facet name="major">
    <timeAxis scale="weeks"/>
  </f:facet>
  <f:facet name="minor">
    <timeAxis scale="days"/>
  </f:facet>
  <f:facet name="nodeStamp">
    <af:column sortProperty="FirstName" sortable="false"
             headerText="#{bindings.OrderShippingSummary2.hints.FirstName.label}">
      <af:outputText value="#{row.FirstName}"/>
    </af:column>
  </f:facet>
    <af:column sortProperty="LastName" sortable="false"
             headerText="#{bindings.OrderShippingSummary2.hints.LastName.label}">
      <af:outputText value="#{row.LastName}"/>
    </af:column>
    <af:column sortProperty="OrderDate" sortable="false"
             headerText="#{bindings.OrderShippingSummary2.hints.OrderDate.label}">
       <af:outputText value="#{row.OrderDate}">
         <af:convertDateTime
             pattern="#{bindings.OrderShippingSummary2.hints.OrderDate.format}"/>
       </af:outputText>
     </af:column>
     <af:column sortProperty="ShippedDate" sortable="false"
         headerText="#{bindings.OrderShippingSummary2.hints.ShippedDate.label}">
       <af:outputText value="#{row.ShippedDate}">
       <af:convertDateTime
         pattern="#{bindings.OrderShippingSummary2.hints.ShippedDate.format}"/>
       </af:outputText>
     </af:column>
     <af:column sortProperty="TaskType" sortable="false"
         headerText="#{bindings.OrderShippingSummary2.hints.TaskType.label}">
       <af:outputText value="#{row.TaskType}"/>
     </af:column>
 </projectGantt>

26.6.3 What You May Need to Know About Summary Tasks in a Project Gantt Chart

A summary task shows start time and end time for a group of tasks (which are usually subtasks). A summary task cannot be moved or extended. However, your application should recalculate the summary task times when the dates of any subtask changes.

To detect a change in task duration, register an event handler by specifying a method binding expression on the DataChangeListener attribute of the Gantt chart component. When an action occurs that potentially changes data in the Gantt chart, the event fired is of type oracle.adf.view.faces.bi.event.DataChangeEvent. This event contains information about the data changes and is fired to the registered event listener. The listener is responsible for validating the new values and updating the underlying data model.

When the update is completed, the Gantt chart is refreshed with either the old data (if the update failed) or with the new data. The Gantt chart uses partial page rendering so that only the Gantt chart and not the entire page is refreshed.

26.6.4 What You May Need to Know About Percent Complete in a Project Gantt Chart

Percent complete can be represented as an inner bar that indicates what percentage of a task is complete. The length of the inner bar is calculated based on percent complete returned by the data object.

The data binding dialog for the project Gantt chart does not provide a control in which you can enter the percentage complete value, but this value is required to render a percent complete. However, the Gantt chart data object does contain a percentComplete attribute.

To provide the percent complete integer, you must add a new attribute mapping in the nodeDefinition for type Tasks. For example, if your data collection has a column named PercentDone, then the attribute mapping would appear as follows: <Item Value="PercentDone" type="percentComplete"/>.

Example 26-22 shows the percent complete attribute mapping added to the data binding code for the nodeDefinition of type Tasks in the project Gantt chart binding displayed in Example 26-20.

Example 26-22 Bindings for Project Gantt Chart with Percent Complete

<nodeDefinition DefName="oracle.fod.model.OrderShippingSummary"
                type="Tasks">
  <AttrNames>
    <Item Value="PersonId" type="taskId"/>
    <Item Value="OrderDate" type="startTime"/>
    <Item Value="TaskType" type="taskType"/>
    <Item Value="ShippedDate" type="endTime"/>
    <Item Value="PercentDone" type="percentComplete"/>
  </AttrNames>

Another attribute (completedThrough) exists that allows you to specify a date rather than a percentage. The Gantt chart data object calculates the percentage complete based on the date that the completedThrough attribute references. For example, if your data collection has a column named PercentDone, then the attribute mapping would appear as follows: <Item Value="PercentDone" type="completedThrough"/>.

26.6.5 What You May Need to Know About Variance in a Project Gantt Chart

Variance can be rendered within two horizontal bars. One bar represents the base (or original) start and end time for the task. The second bar represents the actual start and end time for the task. You enter the binding information for the base start time and end time in the data binding dialog for a project Gantt chart.

The data binding dialog for Gantt chart does not provide controls in which you can enter the actual start time and actual end time for the Gantt chart, but these values are required to render variance. However, the Gantt chart data object does contain the following attributes: actualStart and actualEnd.

To provide the actual start and actual end time, you must add two new attribute mappings in the nodeDefinition for type Tasks. For example, if your data collection has columns named ActualStartDate and ActualEndDate, then the attribute mappings would appear as shown in Example 26-23.

Example 26-23 Attribute Mappings for Actual Start and Actual End

<Item Value="ActualStartDate" type="actualStart"/>
<Item Value="ActualEndDate" type="actualEnd"/>

Example 26-24 shows the actual start and actual end attribute mappings added to the data binding code for the nodeDefinition of type Tasks for a project Gantt chart.

Example 26-24 Bindings for Project Gantt Chart with Actual Start and Actual End

<nodeDefinition DefName="oracle.fod.model.OrderShippingSummary"
                        type="Tasks">
          <AttrNames>
            <Item Value="PersonId" type="taskId"/>
            <Item Value="OrderDate" type="startTime"/>
            <Item Value="TaskType" type="taskType"/>
            <Item Value="ShippedDate" type="endTime"/>
            <Item Value="ActualStartDate" type="actualStart"/>
            <Item Value="ActualEndDate" type="actualEnd"/>
          </AttrNames>

26.6.6 How to Create a Databound Resource Utilization Gantt Chart

For a resource utilization Gantt chart, you must supply identification for resources, identification for time, and start and end times for resource usage. Optionally, you can provide data values for subresources.

The resource utilization Gantt chart is displayed with default values for the major and minor time axis values. In a resource utilization Gantt chart, the setting for the major time axis defaults to weeks and the setting for the minor time axis defaults to days.

Figure 26-42 shows a resource utilization Gantt chart that lists each resource and an associated calendar that can display when the resource is in use.

Figure 26-42 Resource Utilization Gantt Chart

Resource utilization Gantt chart

To create a resource utilization Gantt chart using a data control, you bind the resource utilization component to a data collection. JDeveloper allows you to do this declaratively by dragging a collection from the Data Controls panel and dropping it on a JSF page.


Tip:

You can also create a resource utilization Gantt chart by dragging a resource utilization Gantt chart component from the Component Palette and completing the Create Resource Utilization Gantt dialog. This approach gives you the option of designing the Gantt chart user interface before binding the component to data.


To create a resource utilization Gantt chart:

  1. From the Data Controls panel, select a data collection. For a Gantt chart, you can select a row set collection or a basic tree collection.

    Figure 26-43 shows an example where you could select the GanttRugResourcesView1 collection in the Data Controls panel to create a resource utilization Gantt chart to display the usage of a resource.

    Figure 26-43 Data Collection for Resource Utilization

    Data collection for resource utilization
  2. Drag the collection onto a JSF page and, from the context menu, choose Gantt > Resource Utilization.

  3. In the Create Resource Utilization Gantt dialog, connect resource- and time-related controls with corresponding columns in the data collection.

    1. For Resource Id, select the column in the data collection that corresponds to the unique identifier of the resource.

    2. In the Time Buckets page, select a value from the Bucket Accessor dropdown list that contains the time buckets assigned to the resource and select a value from the Bucket Date dropdown list that corresponds to a unit of time.

    3. In the Bucket Metrics list, you can optionally specify attributes that appear as bars within the time bucket. Each attribute that you specify in the Bucket Metrics list must be of type Number as the value of the attribute is used to calculate the height of the bar.

    4. In the Table Columns list, specify the column(s) to appear in the list region of the Gantt chart resource utilization on the left side of the splitter. Specify one row of information for each column that is to appear. Use the New icon to add new rows. Use the arrow icon to arrange the rows in the exact sequence that you want the columns to appear in the resource utilization list. For each row, provide values for Display Label, Value Binding, and Component to Use.

    5. If the data collection has an accessor for subresources, you can use the Subresources page to select a subresources accessor and a resource ID.

  4. Click OK.

    Figure 26-44 shows the dialog used to create a resource utilization Gantt chart from the data collection for resources available for a project.

    Figure 26-44 Create Resource Utilization Gantt Chart

    Create resource utilization gantt

26.6.7 What Happens When You Create a Resource Utilization Gantt Chart

Dropping a resource utilization Gantt chart from the Data Controls panel onto a JSF page has the following effects:

  • Creates bindings for the resource utilization Gantt chart and adds the bindings to the page definition file

  • Adds the necessary code for the UI components to the JSF page

Example 26-25 shows the row set bindings that were generated for the resource utilization Gantt chart illustrated in Figure 26-44.

Example 26-25 Binding XML for a Resource Utilization Gantt Chart

<gantt IterBinding="GanttRugResourcesView2Iterator"
   id="GanttRugResourcesView2"
   xmlns="http://xmlns.oracle.com/adfm/dvt">
<ganttDataMap>
<nodeDefinition DefName="model.GanttRugResourcesView" type="Resources">
  <AttrNames>
    <Item Value="ResourceId" type="resourceId"/>
  </AttrNames>
  <Accessors>
    <Item Value="GanttRugTimebucketsView2" type="timeBuckets"/>
  </Accessors>
</nodeDefinition>
<nodeDefinition type="TimeBuckets"
                DefName="model.GanttRugTimebucketsView">
  <AttrNames>
    <Item Value="TimeDaily" type="time"/>
    <Item type="metric" Value="Available"/>
    <Item type="metric" Value="Setup"/>
    <Item type="metric" Value="Used"/>
  </AttrNames>
</nodeDefinition>
<nodeDefinition type="Subresources">
  <AttrNames/>
</nodeDefinition>
</ganttDataMap>
</gantt>

Example 26-26 shows the code generated on the JSF page for the resource utilization Gantt chart. This tag code contains settings for the overall start and end time for the resource utilization Gantt chart. These settings have to be edited manually. The code also shows the time axis settings for the major time axis (in weeks) and the minor time axis (in days). Finally, it lists the specifications for each column to appear in the list region of the resource utilization Gantt chart.

Example 26-26 Code on the JSF Page for a Resource Utilization Gantt Chart

<dvt:resourceUtilizationGantt id="resourceUtilizationGantt1"
        value="#{bindings.GanttRugResourcesView2.resourceUtilizationGanttModel}"
        var="row"
        metrics="#{bindings.GanttRugResourcesView2.metrics}"
        taskbarFormatManager="#{bindings.GanttRugResourcesView2.resourceUtilizationGanttTaskbarFormatManager}"
        startTime="2008-07-03"
        endTime="2008-07-29">
  <f:facet name="major">
    <dvt:timeAxis scale="weeks"/>
  </f:facet>
  <f:facet name="minor">
    <dvt:timeAxis scale="days"/>
  </f:facet>
  <f:facet name="nodeStamp">
    <af:column sortProperty="ResourceId" sortable="false"
               headerText="#{bindings.GanttRugResourcesView2.hints.ResourceId.label}">
      <af:outputText value="#{row.ResourceId}"/>
    </af:column>
  </f:facet>
  <af:column sortProperty="ResourceName" sortable="false"
             headerText="#{bindings.GanttRugResourcesView2.hints.ResourceName.label}">
    <af:outputText value="#{row.ResourceName}"/>
  </af:column>
  <af:column sortProperty="ServiceRegion" sortable="false"
             headerText="#{bindings.GanttRugResourcesView2.hints.ServiceRegion.label}">
    <af:outputText value="#{row.ServiceRegion}"/>
  </af:column>
</dvt:resourceUtilizationGantt>

26.6.8 How to Create a Databound Scheduling Gantt Chart

For a scheduling Gantt chart, you must supply identification for resources, identification for tasks, and start and end times for tasks. Optionally, you can provide data values for subresources, recurring tasks, split tasks, and dependencies between tasks.

The scheduling Gantt chart is displayed with default values for overall start and end time and for the major and minor time axis values. In a scheduling Gantt chart, the setting for the major time axis defaults to weeks and the setting for the minor time axis defaults to days.

Figure 26-45 shows a scheduling Gantt chart that lists each resource and all the orders for which that resource is responsible. In contrast to a project Gantt chart, the scheduling Gantt chart shows all the tasks for a given resource on the same line, while the project Gantt chart lists each task on a separate line.

Figure 26-45 The Scheduling Gantt Chart for Order Shipping

Figure described in surrounding text.

To create a scheduling Gantt chart using a data control, you bind the schedulingGantt tag to a data collection. JDeveloper allows you to do this declaratively by dragging and dropping a collection from the Data Controls panel.

To create a databound scheduling Gantt chart:

  1. From the Data Controls panel, select a data collection. For a Gantt chart, you can select a row set collection or a basic tree collection.

    Figure 26-46 shows an example where you could select the Persons data collection to create a scheduling Gantt chart that displays the orders that each resource is responsible for.

    Figure 26-46 Data Collection for Resources

    Data collection for resources
  2. Drag the collection onto a JSF page and, from the context menu, choose Gantt, then Scheduling.

  3. In the ensuing Create Scheduling Gantt dialog, you do the following to connect resource- and task-related controls at the top of the dialog with corresponding columns in the data collection:

    1. For Resource Id, select the column in the data collection that corresponds to the unique identifier of the resource.

    2. In the Tasks page select a value from the Task Accessor dropdown list that contains the tasks assigned to the resource. Select the columns in the data collection that correspond to each of the following controls: Task Id, Start Time, and End Time. You can optionally specify a data column to map to task type. If you do not bind task type to data, then all task types default to Normal.

    3. If the data collection has an accessor that holds dependent tasks, you have the option of using the Dependent Tasks page in the dialog to select the dependent tasks accessor and to select the columns in that data collection that correspond to each of the following controls: Dependency Type, From Task Id, and To Task Id.

    4. If the data collection has an accessor for split tasks, you have the option of using the Split Tasks page in the dialog to select the split tasks accessor and to select the columns in that data collection that correspond to each of the following controls: Split Task Id, Start Time, and End Time.

    5. If the data collection has an accessor for recurring tasks, you have the option of using the Recurring Tasks page in the dialog to select the Recurring Tasks accessor and to select the columns in that data collection that correspond to each of the following controls: Recurring Task Id, Type, Start Time, and End Time.

    6. If the data collection has an accessor for subresources (lower-level resources), you have the option of using the Subresouces page to specify the appropriate accessor and to select the data column that contains the unique identifier of the subresource.

      For example, a manager might be a resource and his direct reports might be subresources. If data contains subresources, then you can drill in a resource to locate subresources.

  4. In the Table Columns section, you specify the columns that will appear in the list region of the Gantt chart on the left side of the splitter. Specify one row of information for each column that is to appear. Use the New icon to add new rows. Use the arrow icon to arrange the rows in the exact sequence that you want the columns to appear in the Gantt chart list. For each row, you provide the following specifications:

    • Display Label: Select the values for the headers of the columns in the Gantt chart list. If you select <default>, then the text for the header is automatically retrieved from the data binding.

    • Value Binding: Select the columns in the data collection to use for the column in the Gantt chart list. The available values are the same as those for the tasks group.

    • Component to Use: Select the type of component to display in the cell of the Gantt chart list. The default is the ADF Output Text component.

  5. Click OK to dismiss the Create Scheduling Gantt dialog.

  6. Select the dvt:schedulingGantt element in the Structure window of the JSF page and set dates for the following attributes of the dvt:schedulingGantt element in the Property Inspector:

    • StartTime

    • EndTime

    The dates that you specify determine the initial view that appears in the scheduling Gantt chart at runtime.

Figure 26-47 shows the dialog used to create the scheduling Gantt chart from the data collection for resources responsible for shipping orders.

Figure 26-47 Create Scheduling Gantt Dialog

CreateScheduling Gantt dialog

26.6.9 What Happens When You Create a Scheduling Gantt Chart

Dropping a scheduling Gantt chart from the Data Controls panel has the following effect:

  • Creates the bindings for the Gantt chart and adds the bindings to the page definition file

  • Adds the necessary code for the UI components to the JSF page

Example 26-27 shows the row set bindings that were generated for the scheduling Gantt chart that displays resources and orders shipped.

Example 26-27 Binding XML for a Scheduling Gantt Chart

<gantt IterBinding="PersonsIterator" id="Persons"
           xmlns="http://xmlns.oracle.com/adfm/dvt">
      <ganttDataMap>
        <nodeDefinition DefName="oracle.fodemo.storefront.store.queries.PersonsVO"
                        type="Resources">
          <AttrNames>
            <Item Value="PersonId" type="resourceId"/>
          </AttrNames>
          <Accessors>
            <Item Value="OrdersVO" type="tasks"/>
          </Accessors>
        </nodeDefinition>
        <nodeDefinition type="Tasks"
                        DefName="oracle.fodemo.storefront.store.queries.OrdersVO">
          <AttrNames>
            <Item Value="OrderId" type="taskId"/>
            <Item Value="OrderDate" type="startTime"/>
            <Item Value="OrderStatusCode" type="taskType"/>
            <Item Value="OrderShippedDate" type="endTime"/>
          </AttrNames>
        </nodeDefinition>
        <nodeDefinition type="Dependents">
          <AttrNames/>
        </nodeDefinition>
        <nodeDefinition type="SplitTasks">
          <AttrNames/>
        </nodeDefinition>
        <nodeDefinition type="RecurringTasks">
          <AttrNames/>
        </nodeDefinition>
        <nodeDefinition type="Subresources">
          <AttrNames/>
        </nodeDefinition>
      </ganttDataMap>
    </gantt>

Example 26-28 shows the code generated on the JSF page for the scheduling Gantt chart. This tag code contains settings for the overall start and end time for the scheduling Gantt chart. It also shows the time axis settings for the major time axis (in months) and the minor time axis (in weeks). Finally, it lists the specifications for each column that appears in the list region of the Gantt chart. For brevity, the code in the af:column elements for MembershipId, Email, and PhoneNumber has been omitted.

Example 26-28 Code on the JSF Page for a Scheduling Gantt Chart

<dvt:schedulingGantt id="schedulingGantt1"
                     value="#{bindings.Persons.schedulingGanttModel}"
                     var="row" startTime="2008-03-29"
                     endTime="2008-05-30"
                     taskbarFormatManager="#{GanttBean.taskbarFormatManager}">
  <f:facet name="major">
    <dvt:timeAxis scale="months"/>
  </f:facet>
  <f:facet name="minor">
    <dvt:timeAxis scale="weeks"/>
  </f:facet>
  <f:facet name="nodeStamp">
        <af:column sortProperty="FirstName" sortable="false"
     headerText="#{bindings.Persons.hints.FirstName.label}">
     <af:outputText value="#{row.FirstName}"/>
     </af:column>
     </f:facet>
     <af:column sortProperty="LastName" sortable="false"
            headerText="#{bindings.Persons.hints.LastName.label}">
            <af:outputText value="#{row.LastName}"/>
          </af:column>
          ...
          <dvt:ganttLegend>
</dvt:schedulingGantt>

26.7 Creating Databound Timelines

A timeline is an interactive data visualization tool that allows users to view date-based events in chronological order and easily navigate forwards and backwards within a defined time range. A dual timeline can be used for a side-by-side comparison of events. For example, you can use a timeline to display the hire dates of employees, or use a dual timeline to compare multiple human resource events between two employees.

A timeline is composed of the display of events as timeline items along a time axis, a movable overview window that corresponds to the period of viewable time in the timeline, and an overview time axis that displays the total time increment for the timeline. A horizontal zoom control is available to change the viewable time range. Timeline items corresponding to events display associated information or actions and are connected to the date of the event in the time axis. Timelines items are represented by a marker in the overview panel. No more that two series of events are supported by the timeline component.

Figure 26-48 shows a timeline displaying the chronological order of the hire dates of employees in the Summit DVT example. In this example, timeline items representing each event display information about the employee using an image and text with labels. When selection is configured, the timeline item, line feeler, and the event marker in the overview panel are highlighted.

Figure 26-48 Timeline of Employee Hire Dates

Timeline of Employee Hire Dates

Figure 26-49 shows a dual timeline comparing multiple human resource events between two employees. The time axis is positioned between the two series of events and the overview panel displays at the bottom of the timeline.

Figure 26-49 Dual Timeline Events Between Employees

Dual Timeline Events Between Employees

The content of timeline items, marker display, and time axis are configurable. For detailed information about timeline use cases, end user and presentation features, tag structure, and adding special features to timelines, see the "Using Timeline Components" chapter in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

26.7.1 How to Create a Timeline Using ADF Data Controls

The data displayed in a timeline is based on data collections. The timeline component uses a model to access the data in the underlying list. The specific model class is oracle.adf.view.rich.model.CollectionModel. You can also use other model instances, for example, java.util.List, java.util.Array, and javax.faces.model.DataModel. The data layer will automatically convert the instance into a CollectionModel.

Stamping is used to associate information about a timeline event with a row of data in a data collection. Using stamping, each row of data in the data model can be displayed for an event. When you use stamping, child components are not created for every item in the timeline. Rather, the content of the component is repeatedly rendered, or stamped, once per data attribute.

Using data controls in Oracle ADF, JDeveloper makes this a declarative task. You drag and drop a data collection from the Data Controls panel that generates one (up to two) series of events onto the JSF page.

Before you begin:

It may be helpful to have an understanding of databound timelines. For more information, see Section 26.7, "Creating Databound Timelines."

You will need to complete these tasks:

To create a timeline using the Data Controls panel:

  1. From the Data Controls panel, select a collection.

    Figure 26-50 shows the data collection for the timeline in Figure 26-48. In this example the Summit DVT application uses the SEmpView1 data collection to create the timeline.

    Figure 26-50 Sample Data Collection for Timeline

    Sample Data Collection for Timeline
  2. Drag the collection onto the JSF page, and from the context menu choose Timeline.

  3. In the Configure Timeline Series Data page of the Create Timeline wizard, configure the timeline data model for at least one (at most two for a dual timeline), by setting the following values:

    1. Series Value: Use the dropdown list to select the data collection to use in the timeline. By default, the data collection you inserted from the Data Controls panel is displayed. JDeveloper automatically lists any data collection from the application module that includes at least one qualifying date-based attribute from which to choose.

    2. Item Date Value: Use the dropdown list to select the date-based attribute to use for the timeline items stamped in the timeline. JDeveloper automatically lists all qualifying attributes in the data collection referenced in the Series Value from which to choose.

    3. Group: Optionally use the dropdown list to select the attribute to use to group timeline items when the item date values are identical. JDeveloper automatically lists all data collection attributes from which to choose.

      You can also choose Expression Builder and create an EL Expression to specify grouping of attributes at runtime. If you need help press F1 or click Help.

  4. For each timeline series that you configured as a data model, select the series, and set the following values for the timeline item display attributes:

    1. Image: Optionally, enter the relative path to the image file to stamp in the timeline item, or use the Search icon to open the Select Image File dialog to navigate to the image source.

      You can also choose Expression Builder to configure an EL Expression that evaluates at runtime to locate the image file.


      Note:

      if you need to change the size of the image in the timeline item, specify the InlineStyle attribute of the af:image component in source code or declaratively in the Property window. For example, in the Summit DVT sample, specify inlineStyle="width:85px;height:100px;".


    2. Component: From the dropdown list, select the ADF Faces component to use to display the attribute text in the timeline item. You can choose from outputText, which displays unformatted text, and outputFormatted, which displays text and can include a limited range of formatting options. You can also choose to associate a label with either output text option in the Label value.

    3. Value: From the dropdown list select the attribute value to display in the timeline item. JDeveloper automatically lists all attributes in the data collection for the selected timeline series.

    4. Label: This option is available if you specify an ADF Faces component with a label in the Component value for the display attribute. You can use the default Use Attribute Name text, specify a text resource from a resource bundle, or use the EL Expression builder to evaluate the label text at runtime. The label displays in the timeline item at runtime.

    For example, to specify the timeline series and display attributes for the DVT Summit sample in Figure 26-48, complete the Configure Timeline Series Data page of the Create Timeline wizard as shown in Figure 26-51.

    Figure 26-51 Configure Timeline Series Data Page of Create Timeline Wizard

    Configure Timeline Series Data Page of wizard
  5. Select Next to advance to the next page of the wizard, Finish to complete the definition of the data binding, or Cancel to end the creation of the timeline.

  6. In the Configure Event Marker page of the Create Timeline Wizard, for each timeline series that you configured as a data model, select the series, and set the following optional values for the event marker:

    1. Color: Specify the fill color for the event marker. You can use the dropdown list to select available colors, or click the icon to display a color picker dialog. By default, no color is specified.

    2. Opacity: Specify the opacity of the fill color of the marker. Valid values range from 0 percent for transparent, to 100 percent for opaque.

    3. Standard Shape: Specify the shape of the overview marker for each selected timeline series value. From the dropdown list, select one of seven prebuilt shapes to style the overview marker shape. Valid values are circle (default), diamond, human, plus, square, triangleDown, and triangleUp.

    4. ScaleX/ScaleY: Enter the horizontal (scaleX) and vertical (scaleY) scale factor to modify the overview marker from its default size. Valid values are numerical percentages from 0 to 100 percent. JDeveloper will automatically resize a marker to fit within the timeline overview area if the marker is too large.

    For example, to specify the timeline overview series markers for the DVT Summit sample in Figure 26-48, complete the Configure Event Marker page of the Create Timeline wizard as shown in Figure 26-52.

    Figure 26-52 Configure Event Marker Page of Create Timeline Wizard

    Configure Event Marker Page of Create Timeline Wizard
  7. Select Back to return to the last page of the wizard, Next to advance to the next page of the wizard, Finish to complete the definition of the data binding, or Cancel to end the creation of the timeline.

  8. In the Configure Time Range and Scale of the Create Timeline Wizard, configure the time axis and overview axis by setting the following values:

    1. Start Time: Enter the starting date to use for the time range of the timeline using the format yyyy-mm-dd. Select a start date that will include events in the data collection you wish to display on the timeline. From the dropdown list you can select Current Date. You can also click the Calendar icon to display a date picker dialog. The current date is the default value.

    2. End Time: Enter the ending date to use for the timeline time range using the format yyyy-mm-dd. Select an end date that will include events in the data collection you wish to display on the timeline. From the dropdown list you can select Current Date. You can also click the Calendar icon to display a date picker dialog. The current date is the default value.

    3. Axis Scale: Use the dropdown list to select the time scale to use for the timeline time axis. The time axis shows the user the current time increment for the timeline.

      You must use a smaller time scale than the Overview Scale. For example, you cannot set the axis scale to years if the overview scale is set to months. You can also specify a custom axis scale.

      Valid values are twoyears, years, halfyears, quarters (default), twomonths, months, twoweeks, weeks, days, sixhours, threehours, hours, halfhours, and quarterhours. You can also specify a custom axis scale. For more information, see "Customizing Timeline Display Elements" in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

    4. Overview Scale: Use the dropdown list to select the time scale to use for the timeline overview axis. The overview axis shows the user the total time increment covered by the timeline.

      Valid values are twoyears, years (default), halfyears, quarters, twomonths, months, twoweeks, weeks, days, sixhours, threehours, hours, halfhours, and quarterhours. You can also specify a custom axis scale. For more information, see "Customizing Timeline Display Elements" in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

    For example, to specify the timeline axis and overview time range for the DVT Summit sample in Figure 26-48, complete the Configure Time Range and Scale page in the Create Timeline wizard as show in Figure 26-53,

    Figure 26-53 Configure Time Range and Scale Page of Create Timeline Wizard

    Configure Time Range and Scale Page of Wizard
  9. Select Back to return to the last page of the wizard, Finish to complete the definition of the data binding, or Cancel to end the creation of the timeline.

26.7.2 What Happens When You Use Data Controls to Create a Timeline

When you use ADF data controls to create a timeline, JDeveloper:

  • Defines the bindings for the timeline in the page definition file of the JSF page, and

  • Inserts code in the JSF page for the DVT timeline components.

Example 26-29 shows the bindings defined in the page definition file of the JSF page for the DVT Summit sample timeline in Figure 26-48.

Example 26-29 XML Bindings in Page Definition File

<bindings>
  <tree IterBinding="SEmpView1Iterator" id="SEmpView1" ChangeEventPolicy="ppr">
    <nodeDefinition DefName="model.SEmpView" Name="SEmpView1">
      <AttrNames>
        <Item Value="DeptId"/>
        <Item Value="FirstName"/>
        <Item Value="Id"/>
        <Item Value="LastName"/>
        <Item Value="StartDate"/>
      </AttrNames>
    </nodeDefinition>
  </tree>
</bindings>

Example 26-30 shows the code inserted in the JSF page for the example timeline in Figure 26-48.

Example 26-30 Sample Code for Timeline Component

<dvt:timeline id="tl1" startTime="2010-01-01" endTime="2012-12-31"
      itemSelection="multiple">
  <dvt:timelineSeries id="ts1" var="evt"
        value="#{bindings.SEmpView1.collectionModel}">
    <dvt:timelineItem value="#{evt.StartDate}" id="ti1" group="#{evt.DeptId}">
      <af:panelGroupLayout id="pg1" layout="horizontal">
        <af:image id="img1" source="images/#{evt.Id}.png"
            inlineStyle="width:85px;height:100px;"/>
        <af:spacer width="3" id="s1"/>
          <af:panelGroupLayout id="pg2" layout="vertical">
            <af:panelLabelAndMessage id="plam1"
                  label="#{viewcontrollerBundle.EMPLOYEE_ID}">
            <af:outputText id="ot1" value="#{evt.Id}" noWrap="true">
            <af:convertNumber groupingUsed="false" pattern=
                  "#{bindings.SEmpView1.hints.Id.format}"/>
            </af:outputText>
            </af:panelLabelAndMessage>
            <af:panelLabelAndMessage id="plam2"
                  label="#{viewcontrollerBundle.FIRST_NAME}">
            <af:outputText id="ot2" value="#{evt.FirstName}" noWrap="true"/>
            </af:panelLabelAndMessage>
            <af:panelLabelAndMessage id="plam3"
                  label="#{viewcontrollerBundle.LAST_NAME}">
            <af:outputText id="ot3" value="#{evt.LastName}" noWrap="true"/>
            </af:panelLabelAndMessage>
            <af:panelLabelAndMessage id="plam4"
                  label="#{viewcontrollerBundle.DEPARTMENT_ID}">
            <af:outputText id="ot4" value="#{evt.DeptId}" noWrap="true">
            <af:convertNumber groupingUsed="false" pattern=
                  "#{bindings.SEmpView1.hints.DeptId.format}"/>
            </af:outputText>
            </af:panelLabelAndMessage>
            </af:panelGroupLayout>
          </af:panelGroupLayout>
            <f:facet name="overviewItem">
              <dvt:marker id="m1" fillColor="#ff0000"/>
            </f:facet>
        </dvt:timelineItem>
     </dvt:timelineSeries>
       <dvt:timeAxis id="ta1" scale="months"/>
       <dvt:timelineOverview id="ov1">
       <dvt:timeAxis id="ta2" scale="halfyears"/>
     </dvt:timelineOverview>
   </dvt:timeline>

26.7.3 What You May Need to Know About Using Data Controls to Create a Dual Timeline

When you use the Data Controls panel to create a dual timeline, you can configure the same or different data collections to configure the two timeline series and specify the timeline item display attributes and overview marker for each one. JDeveloper automatically lists any data collection from the application module that includes at least one qualifying date-based attribute from which to choose in the Create Timeline wizard.

Example 26-31 show the sample code for the dual timeline displayed in Figure 26-49.

Example 26-31 Sample Code for a Dual Timeline

<dvt:timeline id="tl1" startTime="2000-01-01" endTime="2011-12-31"
      inlineStyle="width:1024px;height:500px" itemSelection="single"
      currentTime="2010-04-01">
  <dvt:timelineSeries id="ts1" var="evt" value="#{timeline.firstModel}"
        contentDelivery="lazy">
    <dvt:timelineItem id="ti1" value="#{evt.date}" group="#{evt.group}">
      <af:panelGroupLayout id="pg1" layout="horizontal">
        <af:image id="img1" inlineStyle="width:30px;height:30px"
               source="/resources/images/timeline/#{evt.type}.png"/>
        <af:spacer width="3"/>
          <af:panelGroupLayout id="pg2" layout="vertical">
            <af:outputText id="ot1" inlineStyle="color:#084B8A"
                  value="#{evt.description}" noWrap="true"/>
            <af:outputText id="ot2" value="#{evt.date}"
                  inlineStyle="color:#6e6e6e" noWrap="true">
            <af:convertDateTime dateStyle="medium"/>
            </af:outputText>
          </af:panelGroupLayout>
      </af:panelGroupLayout>
        <f:facet name="overviewItem">
          <dvt:marker id="m1" shape="circle" fillColor="#ff0000"/>
        </f:facet>
    </dvt:timelineItem>
  </dvt:timelineSeries>
  <dvt:timelineSeries id="ts2" var="evt" value="#{timeline.secondModel}"
        contentDelivery="lazy">
    <dvt:timelineItem id="ti2" value="#{evt.date}">
      <af:panelGroupLayout id="pg2" layout="horizontal">
        <af:image id="img2" inlineStyle="width:30px;height:30px"
              source="/resources/images/timeline/#{evt.type}.png"/>
        <af:spacer width="3"/>
          <af:panelGroupLayout id="pg3" layout="vertical">
            <af:outputText id="ot3" inlineStyle="color:#084B8A"
                  value="#{evt.description}" noWrap="true"/>
            <af:outputText id="ot4" value="#{evt.date}"
                  inlineStyle="color:#6e6e6e" noWrap="true">
            <af:convertDateTime dateStyle="medium"/>
            </af:outputText>
          </af:panelGroupLayout>
        </af:panelGroupLayout>
        <f:facet name="overviewItem">
          <dvt:marker id="m2" shape="circle" fillColor="#0000ff"/>
        </f:facet>
      </dvt:timelineItem>
    </dvt:timelineSeries>
    <dvt:timeAxis id="ta1" scale="quarters"/>
      <dvt:timelineOverview id="ov1">
        <dvt:timeAxis id="ta2" scale="years"/>
      </dvt:timelineOverview>
</dvt:timeline>

For information about the data requirements, tag structure, and options for customizing the look and behavior of the component, see the "Using Timeline Components" chapter in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

26.8 Creating Databound Hierarchy Viewers

A hierarchy viewer is an ADF Data Visualization component that visually displays data where parent-child relationships exist within the data. This component is useful where you want to display organization charts, network diagrams, or social networks, for example.

Figure 26-54 shows a runtime view of a hierarchy viewer component that renders an organization chart.

Figure 26-54 Hierarchy Viewer Component Rendering an Organization Chart

hierarchy viewer as an organizational chart

Figure 26-55 shows the Component Gallery displaying the types of hierarchy viewers and the quick start layouts that you can use to create a hierarchy viewer.

Figure 26-55 Component Gallery for Hierarchy Viewer Types

Component gallery for hierarchy viewer

Each hierarchy viewer component (dvt:hierarchyViewer) that you create can include:

The optional panel card element (dvt:panelCard) can be used in conjunction with the hierarchy viewer component. The panel card provides a method to dynamically switch between multiple sets of content referenced by a node element using animation by, for example, horizontally sliding the content or flipping a node over. You can specify the use of a panel card by choosing the quick start layout selected in Figure 26-55.

For information about customizing a hierarchy viewer after the databinding is complete, see the "Using ADF Hierarchy Viewer Components" chapter in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

26.8.1 How to Create a Databound Hierarchy Viewer

Hierarchy viewers are based on data collections where a master-detail relationship exists between one or more detail collections and a master data collection. Using data controls in Oracle ADF, JDeveloper makes this a declarative task. You drag and drop a data collection from the Data Controls panel that generates one or more root nodes onto a JSF page.

To create a databound hierarchy viewer:

  1. From the Data Controls panel, select a collection.

    Figure 26-56 shows an example where you could select the HvtestView1 collection in the Data Controls panel to create a hierarchy viewer representing the personnel data in an organizational chart.

    Figure 26-56 Data Collection for Personnel Organizational Chart

    Data collection for personnel organizational chart
  2. Drag the collection onto a JSF page and, from the context menu, choose Hierarchy Viewer.

  3. From the Component Gallery, select the layout of the hierarchy viewer you want to create. Figure 26-55, "Component Gallery for Hierarchy Viewer Types" shows the Component Gallery with the vertical top down layout selected.


    Note:

    Other than choosing a quick start layout, the Component Gallery and the subsequent Create Hierarchy Viewer dialog do not allow you to customize the appearance of the hierarchy viewer. To customize the appearance of the hierarchy viewer, set values for the hierarchy viewer using the Property Inspector after you complete this procedure.


  4. In the Create Hierarchy Viewer dialog, do the following:

    • In the Hierarchy list, select the collections you want to include as nodes in the runtime diagram.

    • For each collection that you select in the Hierarchy list, select attributes in the adjoining Node Attributes list to appear, using one or more of the zoom levels available to you. Select Add Zoom Level for each of the 75%, 50%, or 25% levels that you configure.

      The hierarchy viewer component defines four zoom levels. You cannot modify these zoom levels or create new zoom levels. The default zoom level is 100%.

  5. Click OK.

Figure 26-57 shows the Create Hierarchy Viewer dialog that appears if you create a hierarchy viewer using data from a data collection named hvtestView1. In the example, the following is configured for the 100% zoom level:

  • In the Hierarchy area, the data collection HvtestView1 is selected to display the tree binding, and the accessor HvtestView is selected to display the child nodes in the tree.

  • The Quick Start Layout selection specifies that a dvt:panelCard will be configured for the hierarchy viewer node.

  • The Image selection specifies the image file to be stamped in each node. This option is only available for the panel card quick start layout.

  • The Node Attributes selection specifies the contents and order of display in each node, along with the ADF component used to render the content.

Figure 26-57 Create Hierarchy Viewer Dialog for Employees

Create Hierarchy Viewer dialog

After completing the Create Hierarchy Viewer dialog, you can use the Property Inspector to specify settings for the hierarchy viewer attributes, and you can also use the child tags associated with the hierarchy viewer tag to customize the hierarchy further.

26.8.2 What Happens When You Create a Databound Hierarchy Viewer

Creating a hierarchy viewer from Data Controls panel has the following effect:

  • Creates the bindings for the hierarchy viewer in the page definition file of the JSF page

  • Adds the necessary tags to the JSF page for the hierarchy viewer component

Example 26-32 displays bindings that JDeveloper generated for a hierarchy viewer component. The rules for populating the nodes of the component are defined as a node definition. Each node definition references a view object and associated attributes. The example shows that one node definition was generated for all levels in the hierarchy. The code example also references an accessor (HvtestView).

Example 26-32 Bindings for a Hierarchy Viewer

<bindings>
  <tree IterBinding="HvtestView1Iterator" id="HvtestView1">
    <nodeDefinition DefName="model.HvtestView">
      <AttrNames>
        <Item Value="Phone"/>
        <Item Value="Email"/>
        <Item Value="Managerid"/>
        <Item Value="Thumburl"/>
        <Item Value="Lastname"/>
        <Item Value="Firstname"/>
        <Item Value="Id"/>
        <Item Value="Title"/>
      </AttrNames>
      <Accessors>
        <Item Value="HvtestView"/>
      </Accessors>
    </nodeDefinition>
  </tree>
</bindings>

Example 26-33 shows the code generated on the JSF page that is associated with the page definition file in Example 26-32. For brevity, the code in the facet elements named zoom75, zoom50, and zoom25 has been omitted. One of the showDetail items in the panel card element has also been omitted.

The example shows a hierarchy viewer component that references the HvtestView1 tree binding. It includes a node (dvt:node) component that in turn includes a panel card component (dvt:panelCard). The panel card component defines slide_horz as the effect to use when changing the display of content referenced by the node.

It is not possible to customize the layout of a hierarchy viewer component or to add additional components, such as panel cards, using the Create Hierarchy dialog illustrated in Figure 26-57. For this reason, you customize the layout of a hierarchy viewer component directly in the code, in the visual editor, or by setting values in the Property Inspector. You can add additional components, such as panel cards, using the Component Palette.

Example 26-33 Code on the JSF Page for a Hierarchy Viewer

<dvt:hierarchyViewer id="hv1" var="node"
                     value="#{bindings.HvtestView1.treeModel}"
         selectionListener="#{bindings.HvtestView1.treeModel.makeCurrent}"
                     layout="hier_vert_top"
                     levelFetchSize="#{bindings.HvtestView1.rangeSize}"
                     styleClass="AFStretchWidth">
  <dvt:link linkType="orthogonalRounded" id="l1"/>
  <dvt:node type="model.HvtestView" width="233" height="330" id="n1">
    <f:facet name="zoom100">
      <af:panelGroupLayout styleClass="AFStretchWidth AFHVNodeStretchHeight AFHVNodePadding"
                           layout="vertical" id="pgl4">
        <af:panelGroupLayout layout="horizontal" id="pgl3">
          <af:panelGroupLayout id="pgl2">
            <af:image source="images/#{node.Thumburl}"
                      styleClass="AFHVNodeImageSize" id="i1"/>
          </af:panelGroupLayout>
          <af:spacer width="5" height="5" id="s2"/>
          <af:panelGroupLayout layout="vertical" id="pgl1">
            <af:outputText value="#{node.Firstname}"
                           styleClass="AFHVNodeTitleTextStyle" id="ot7"/>
            <af:outputText value="#{node.Lastname}"
                           styleClass="AFHVNodeSubtitleTextStyle" id="ot6"/>
            <af:outputText value="#{node.Title}"
                           styleClass="AFHVNodeTextStyle" id="ot5"/>
          </af:panelGroupLayout>
        </af:panelGroupLayout>
        <af:spacer height="5" id="s3"/>
        <dvt:panelCard effect="slide_horz" styleClass="AFHVNodePadding"
                       id="pc1">
          <af:showDetailItem text="Contact " id="sdi2">
            <af:panelFormLayout styleClass="AFStretchWidth AFHVNodeStretchHeight AFHVNodePadding"
                                id="pfl2">
              <af:panelLabelAndMessage label="#{bindings.HvtestView1.hints.Email.label}"
                                styleClass="AFHVPanelCardLabelStyle"
                                id="plam4">
                <af:outputText value="#{node.Email}"
                               styleClass="AFHVPanelCardTextStyle" id="ot2"/>
              </af:panelLabelAndMessage>
              <af:panelLabelAndMessage label="#{bindings.HvtestView1.hints.Phone.label}"
                                styleClass="AFHVPanelCardLabelStyle"
                                id="plam1">
                <af:outputText value="#{node.Phone}"
                               styleClass="AFHVPanelCardTextStyle" id="ot3"/>
              </af:panelLabelAndMessage>
            </af:panelFormLayout>
          </af:showDetailItem>
          <af:showDetailItem text="Address " id="sdi1">
                 showDetailItem details omitted
          </af:showDetailItem>
        </dvt:panelCard>
      </af:panelGroupLayout>
    </f:facet>
  </dvt:node>
</dvt:hierarchyViewer>

26.8.3 How to Create a Databound Search in a Hierarchy Viewer

The search function in a hierarchy viewer is based on the searchable attributes or columns of the data collection that is the basis of the hierarchy viewer data model. Using a query results collection defined in data controls in Oracle ADF, JDeveloper makes this a declarative task. You drag and drop an ExecuteWithParams operation into an existing hierarchy viewer component on the page.

Before you begin:

  1. You must have a databound hierarchy viewer component present on your page.

  2. Verify the query that retrieves the root node in the hierarchy viewer.

    For example, Figure 26-58 shows retrieving the root node by EMPNO column.

    Figure 26-58 Root Node Query

    Root node query
  3. Create a view object that performs the search.

    For example, Figure 26-59 shows the EmployeesSearchResults view object that performs the search based on the Job column in the data collection with a default value of % for matching any value, and a comparison value of = specifying an exact match against the column.

    Figure 26-59 EmployeeSearchResults View Object

    EmployeesSearchResults view object.

    For information about creating a view object, see Section 5.2.1, "How to Create an Entity-Based View Object."

To create a databound search with a hierarchy viewer:

  1. From the Data Controls panel, select the collection that corresponds to the query results and expand the Operations node to display the ExecuteWithParams operation.

  2. Drag the ExecuteWithParams operation and drop it onto the hierarchy viewer in the visual editor or onto the component in the Structure window. Alternatively, you can drag the parameter onto the hierarchy viewer.

  3. In the Create Hierarchy Viewer Search dialog that displays, use the Add icon to specify the list of results to display in the Search Results panel, and specify the following for each result:

    1. Display Label: Select the values for the headers of the nodes in the hierarchy. If you select <default>, then the text for the header is automatically retrieved from the data binding.

    2. Value Binding: Select the columns in the data collection to use for nodes in the tree for the hierarchy viewer.

    3. Component to Use: Select the type of component to display in the node. The default is the ADF Output Text component.

    After selecting an existing field, use the arrow icons (Up, Down, Top, Bottom) to reorder the results or use the Delete icon to delete that result.

  4. In the Operation dropdown list select the hierarchy root data collection to use when a search result is selected. Valid values include:

    • removeRowWithKey: Uses the row key as a String converted from the value specified by the input field to remove the data object in the bound data collection.

    • setCurrentRowWithKey: Sets the row key as a String converted from the value specified by the input field. The row key is used to set the currency of the data object in the bound data collection.

    • setCurrentRowWithKeyValue: Sets the current object on the iterator, given a key's value.

    • ExecuteWithParams: Sets the values to the named bind variables passed as parameters.

  5. In the Parameter Mapping table, use the dropdown list in the Results Attribute column to select the results collection attribute to map to the parameter displayed in the Hierarchy Parameter column.

Figure 26-60 shows the Create Hierarchy Viewer Search dialog that appears if you create a hierarchy viewer using data from a data collection named EmployeesSearchResults1.

Figure 26-60 Create Hierarchy Viewer Search Dialog

Create Hiearchy Viewer Search dialog.

At runtime, the search results are displayed in a table by Ename and Job. Figure 26-61 shows the resulting search results panel when the user enters "Manager" in the search box and selects one of the search results.

Figure 26-61 Hierarchy Viewer Search Results

Hierarchy viewer search results

26.9 Creating Databound Treemaps and Sunbursts

Treemaps and sunbursts are ADF Data Visualization components that display quantitative hierarchical data across two dimensions, represented visually by size and color. For example, you can use a treemap or sunburst to display quarterly regional sales and to identify sales trends, using the size of the node to indicate each region's sales volume and the node's color to indicate whether that region's sales increased or decreased over the quarter.

Treemaps and sunbursts use a shape called a node to reference the data in the hierarchy. Treemaps display nodes as a set of nested rectangles. Each branch of the tree is given a rectangle, which is then tiled with smaller rectangles representing sub-branches.

Figure 26-62 shows a treemap displaying products available at a company's warehouses in different regions around the world. In this example, the node size represents the amount in stock for each product, and node color represents inventory status.

Figure 26-62 Treemap Showing Product Availability and Inventory Levels

Treemap Showing Products and Inventory Levels

Sunbursts display the nodes in a radial rather than a rectangular layout, with the top of the hierarchy at the center and deeper levels farther away from the center. Figure 26-63 shows the same inventory data displayed in a sunburst.

Figure 26-63 Sunburst Showing Product Availability and Inventory Levels

Sunburst Showing Products and Inventory Levels

The shape and content of the nodes are configurable, as well as the visual layout of the nodes. For detailed information about treemap and sunburst end user and presentation features, use cases, tag structure, and adding special features, see the "Using ADF Treemap and Sunburst Components" chapter in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

26.9.1 How to Create Treemaps and Sunbursts Using ADF Data Controls

Treemaps and sunbursts are based on data collections where a master-detail relationship exists between one or more detail collections and a master data collection. Treemaps and sunbursts also require that the following attributes be set in JDeveloper:

  • value: the size of the node

  • fillColor: the color of the node

  • label: a text identifier for the node

The values for the value and label attributes must be stored in the treemap's or sunburst's data model or in classes and managed beans if you are using UI-first development. You can specify the fillColor values in the data model, classes, and managed beans, or declaratively in the Property Inspector.

In order to configure a treemap or sunburst successfully, ensure that the data adheres to the following rules:

  • Each child node can have only one parent node.

  • There can be no skipped levels.

Using data controls in Oracle ADF, JDeveloper makes treemap and sunburst creation a declarative task. You drag and drop a data collection from the Data Controls panel that generates one or more nodes onto a JSF page.

Before you begin:

You will need to complete these tasks:

To create a treemap or sunburst using the Data Controls panel:

  1. From the Data Controls panel, select a collection.

    Figure 26-64 shows the data collection for the treemap in Figure 26-62 and the sunburst in Figure 26-63. In this example, the application uses a view link between the SCountriesView2 collection and the SWarehouseView2 collection to create a hierarchy consisting of the SRegionView1 and SWarehouseView2 data collections.

    Figure 26-64 Sample Data Collection for Treemap and Sunburst

    Sample Data Collection for Treemap and Sunburst

    Table 26-6 shows the value, size, and color attributes used to create the treemap or sunburst.

    Table 26-6 Sample Values for Treemap and Sunburst Inventory Example

    CollectionSize ValueLabel ValueColor Value

    SRegionView1

    CountryCount

    Name

    Default

    SCountriesView2

    WarehouseCount

    Country

    Default

    SWarehouseView2

    ProductCount

    City

    Default

    ProductInventoryView2

    AmountInStock

    Name

    Varies by stock level


  2. Drag the collection onto a JSF page and, from the context menu, choose Treemap or Sunburst.

  3. In the Create Treemap dialog or Create Sunburst dialog, in the Hierarchy section, select the collections you want to include as nodes in the runtime treemap or sunburst. By default, the root collection is selected.

  4. For each collection that you select in the Hierarchy list, enter a value for the following.

    • Value: From the dropdown list, select the attribute in the data collection that represents the size value for the sunburst. You can select one of the attributes provided or select Expression Builder to enter a JSF EL expression. For help with the Expression Builder dialog, press F1 or click Help.

      For example, to create a treemap or sunburst using the data collection in Figure 26-64, select CountryCount for the SRegionView1 value to represent the size value for the first node.

    • Label: From the dropdown list, select the attribute in the data collection that represents the label you wish to display for the sunburst node label. You can select one of the attributes provided or select Expression Builder to enter a JSF EL expression.

      For example, select Name for the SRegionView1 node label.

    • Optionally, in the View Area section, click New to configure an attribute group for the node. Use attribute groups if you want the node's display to vary based on color or pattern. You can also specify the node's fill color or pattern in the node's fillColor and fillPattern properties after you create the treemap or sunburst.

      If you do not configure an attribute group to vary by color or specify a fillColor attribute on the node, the node will display in black. By default, no pattern will be displayed on the node.

      In the treemap and sunburst product inventory example, attribute groups are configured for each level in the hierarchy.

      To configure an attribute group, enter values for the following:

      • Group by value: From the dropdown list, select the attribute in the data collection to group by in the attribute group. You can select one of the attributes provided or select Expression Builder to enter a JSF EL expression.

        In the treemap and sunburst example, the size value is used as the Group by value. For the SRegionView1 collection, select CountryCount as the Group by value.

      • Area: From the dropdown list, select Color if you want the attribute group to vary by color or select Pattern if you want the attribute group to vary by pattern. To vary the attribute group by both color and pattern, select Select Multiple Attributes and select both Color and Pattern. Click OK.

        In the treemap and sunburst product inventory example, color is used for each level of the hierarchy.

      • Legend Label: From the dropdown list, select the attribute in the data collection to display in the treemap's legend. You can select one of the attributes provided or select Expression Builder to enter a JSF EL expression.

        In the treemap and sunburst product inventory example, this value is left blank.

      Figure 26-65 shows the Create Treemap dialog completed for the first node in the product inventory example. The entries for the Create Sunburst dialog are identical.

      Figure 26-65 Create Treemap Dialog for a Region Node

      Create Treemap Dialog for Region Node
    • Optionally, click Value-Specific Rules to expand the attribute group dialog to specify a match or exception rule. Use match rules to specify colors or patterns for simple true or false conditions or when you want to match a specific value. Use exception rules when you want to specify a color or pattern when the node's grouped-by value meets a specific condition.

      To specify a match rule, in the Match Rules section, click New and enter values for the following:

      • Group Value: Enter the category value for the match. This can be a string that represents a category or you can set this to true or false. If you set this to true or false, the Group by value field must contain an EL expression that evaluates to true or false as in the following example:#{row.AmountInStock gt row.ReorderPoint}.

      • Property: From the dropdown list, select Color if you want the node to vary by color or select Pattern if you want the attribute node to vary by pattern.

      • Property Value: From the dropdown list, select the color or pattern to display when the node's value matches the Group Value. For color, you can select one of the provided values or select Custom Color to enter a custom color in the Select Custom Color dialog. For pattern, you must select one of the provided values.

      Figure 26-66 shows the Create Treemap dialog for a data collection using match rules for the bottom level of the hierarchy. The Create Sunburst dialog entries are identical.

      Figure 26-66 Treemap Showing Match Rules for an Attribute Group

      Treemap Showing Attribute Group Match Rules

      In this example, the treemap nodes will display in green (RGB hexadecimal #008000) when the inventory levels are acceptable and in red (RBG hexadecimal #ff0000) when the inventory level is at or below the product's reorder level. The attribute group's Label field contains the details for the legend display. In this case, the field contains an expression that determines the legend label based on an item's amount in stock: #{(row.AmountInStock gt row.ReorderPoint) ? 'Stock Level OK' : 'Reorder Time'}.

      Figure 26-67 shows the runtime treemap.

      Figure 26-67 Treemap Showing Match Rules at Runtime

      Treemap Showing Match Rules at Runtime

      To specify an exception rule, in the Exception Rules section, click New and enter values for the following:

      • Condition: Enter a JSF EL expression that evaluates to true or false. You can enter the expression directly in the Condition field or select Expression Builder to enter the JSF EL expression.

        In the treemap and sunburst product inventory example, three exception rules are defined for the bottom level of the hierarchy. When the product's inventory level is well above the reorder level, the treemap node in Figure 26-62 and the sunburst node in Figure 26-63 display in green. The treemap and sunburst node display in yellow when the inventory level is close to the reorder point and display in red when the inventory level is at or very near the reorder point.

        Figure 26-68 shows the Create Sunburst dialog for the sample data collection in Figure 26-64 using exception rules for the bottom level of the hierarchy. The Create Treemap dialog entries are identical.

        Figure 26-68 Sunburst Showing Exception Rules Creation Dialog

        Sunburst Showing Exception Rules
      • Property: From the dropdown list, select Color if you want the node to vary by color. Select Pattern if you want the node to vary by pattern.

      • Property Value: From the dropdown list, select the color or pattern to display when the node's value meets the condition you specified in the Condition field. For color, you can select one of the provided values or select Custom Color to enter a custom color in the Select Custom Color dialog. For pattern, you must select one of the provided values.

      • Legend Label: From the dropdown list, select Select Text Resource to select a text resource to be used for the legend label. You can also enter text in this field or select Expression Builder to enter a JSF EL expression.

  5. Click OK.

26.9.2 What Happens When You Create a Databound Treemap or Sunburst

Creating a treemap or sunburst from Data Controls panel has the following effect:

  • Creates the bindings for the sunburst or treemap in the page definition file of the JSF page

  • Adds the necessary tags to the JSF page for the treemap or sunburst component

Example 26-34 displays bindings that JDeveloper generated for a treemap or sunburst component using the data collection in Figure 26-64. Since both components use the same data model, the bindings in the page definition file are identical.

Example 26-34 Sample Bindings for a Treemap or Sunburst

<executables>
  <variableIterator id="variables"/>
  <iterator Binds="SRegionView1" RangeSize="-1" DataControl="AppModuleDataControl"
            id="SRegionView1Iterator"/>
</executables>
<bindings>
  <tree IterBinding="SRegionView1Iterator" id="SRegionView1">
    <nodeDefinition DefName="model.SRegionView" Name="SRegionView10">
      <AttrNames>
        <Item Value="Id"/>
        <Item Value="Name"/>
        <Item Value="CountryCount"/>
      </AttrNames>
      <Accessors>
          <Item Value="SCountriesView"/>
      </Accessors>
    </nodeDefinition>
    <nodeDefinition DefName="model.SCountriesView" Name="SRegionView11">
      <AttrNames>
        <Item Value="Id"/>
        <Item Value="Country"/>
        <Item Value="RegionId"/>
         Item Value="WarehouseCount"/>
      </AttrNames>
      <Accessors>
        <Item Value="SWarehouseView"/>
      </Accessors>
    </nodeDefinition>
    <nodeDefinition DefName="model.SWarehouseView" Name="SRegionView12">
      <AttrNames>
        <Item Value="Id"/>
        <Item Value="Address"/>
        <Item Value="City"/>
        <Item Value="State"/>
        <Item Value="CountryId"/>
        <Item Value="ZipCode"/>
        <Item Value="Phone"/>
        <Item Value="ManagerId"/>
        <Item Value="ProductCount"/>
      </AttrNames>
      <Accessors>
        <Item Value="ProductInventoryView"/>
      </Accessors>
    </nodeDefinition>
    <nodeDefinition DefName="model.ProductInventoryView" Name="SRegionView13">
      <AttrNames>
        <Item Value="ProductId"/>
        <Item Value="WarehouseId"/>
        <Item Value="AmountInStock"/>
        <Item Value="ReorderPoint"/>
        <Item Value="MaxInStock"/>
        <Item Value="OutOfStockExplanation"/>
        <Item Value="RestockDate"/>
        <Item Value="Id"/>
        <Item Value="Name"/>
        <Item Value="ShortDesc"/>
      </AttrNames>
    </nodeDefinition>
  </tree>
</bindings>

The rules for populating the nodes of the treemap or sunburst are defined in node definitions. The example shows that four node definitions were generated, one for each level of the hierarchy. Each of these node definitions references a view object and associated attributes. Each node definition also references an accessor for the next level of the hierarchy if the next level exists.

Once you create your treemap or sunburst, you can modify the value, label, and attribute group for each node using the Create Treemap or Create Sunburst dialog. To open the dialog, use the Edit icon in the Property Inspector for the treemap or sunburst component. You can also customize the values directly in the code or by setting values in the Property Inspector.

26.9.3 What Happens at Runtime: How Databound Sunbursts or Treemaps Are Initially Displayed

By default, a sunburst or treemap displays only the first two levels of the hierarchy and will not display a legend until you configure the legendSource attribute on the sunburst or treemap. Figure 26-69 shows the sunburst that is displayed at runtime if you create the sunburst using the data collection in Figure 26-64.

Figure 26-69 Databound Sunburst Example Before Configuration

Runtime Sunburst Initial Display

After completing the Create Treemap or Create Sunburst dialog, you can use the Property Inspector to configure the treemap or sunburst level display and legendSource attribute. You can also specify settings for other treemap or sunburst attributes and use the child tags associated with the sunburst and treemap tags to customize the components further.

Example 26-35 shows the code on the JSF page code for the treemap in Figure 26-62. In this example, the databound treemap is configured to display all levels in the hierarchy, a legend, and a tooltip when the user hovers the mouse over a node.

Example 26-35 Sample Code on a JSF Page for a Treemap

<dvt:treemap id="t1" value="#{bindings.SRegionView1.treeModel}"
             var="row" displayLevelsChildren="3"
             legendSource="ag1" summary="Sample Treemap">
  <af:switcher facetName="#{row.hierTypeBinding.name}" id="s1">
    <f:facet name="SRegionView11">
      <dvt:treemapNode value="#{row.WarehouseCount}" label="#{row.Country}"
                       id="tn1">
        <dvt:attributeGroups id="ag2" value="#{row.WarehouseCount}" type="color"/>
      </dvt:treemapNode>
    </f:facet>
    <f:facet name="SRegionView10">
      <dvt:treemapNode value="#{row.CountryCount}" label="#{row.Name}" id="tn2">
        <dvt:attributeGroups id="ag3" value="#{row.CountryCount}" type="color"/>
      </dvt:treemapNode>
    </f:facet>
    <f:facet name="SRegionView13">
      <dvt:treemapNode value="#{row.AmountInStock}" label="#{row.Name}" id="tn3"
                       shortDesc="Amount in Stock: #{row.AmountInStock}&lt;br/>Reorder Point: #{row.ReorderPoint}">
        <dvt:attributeGroups value="#{row.AmountInStock}" type="color" id="ag1">
          <dvt:attributeExceptionRule id="aer1"
                                      condition="#{(row.AmountInStock.value - row.ReorderPoint.value) gt 50}"
                                      label="Stock OK">
            <f:attribute name="color" value="#008800"/>
          </dvt:attributeExceptionRule>
          <dvt:attributeExceptionRule id="aer2"
                                      condition="#{((row.AmountInStock.value - row.ReorderPoint.value) le 50) and ((row.AmountInStock.value - row.ReorderPoint.value) gt 25)}"
                                      label="Stock Level Getting Low">
            <f:attribute name="color" value="#FFFF33"/>
          </dvt:attributeExceptionRule>
          <dvt:attributeExceptionRule id="aer3"
                                      condition="#{(row.AmountInStock.value - row.ReorderPoint.value) le 25}"
                                      label="Reord!er Time">
            <f:attribute name="color" value="#880000"/>
          </dvt:attributeExceptionRule>
        </dvt:attributeGroups>
      </dvt:treemapNode>
    </f:facet>
    <f:facet name="SRegionView12">
      <dvt:treemapNode value="#{row.ProductCount}" label="#{row.City}" id="tn4">
        <dvt:attributeGroups id="ag4" value="#{row.ProductCount}" type="color"/>
      </dvt:treemapNode>
    </f:facet>
  </af:switcher>
</dvt:treemap>

Example 26-36 shows the code on the JSF page code for the sunburst in Figure 26-63. In this example, the databound sunburst is also configured to display all levels in the hierarchy, a legend, and a tooltip when the user hovers the mouse over a node. Note the similarities between the sunburst code in this example and the treemap code in the previous example.

Example 26-36 Sample Code on a JSF Page for a Sunburst

<dvt:sunburst id="t1" value="#{bindings.SRegionView1.treeModel}" var="row"
              displayLevelsChildren="3"
              summary="Sample Sunburst" legendSource="ag3">
  <af:switcher facetName="#{row.hierTypeBinding.name}" id="s1">
    <f:facet name="SRegionView10">
      <dvt:sunburstNode value="#{row.CountryCount}" label="#{row.Name}" id="sn1" >
        <dvt:attributeGroups value="#{row.CountryCount}" type="color"
                             label="Country Count" id="ag1"/>
      </dvt:sunburstNode>
    </f:facet>
    <f:facet name="SRegionView11">
      <dvt:sunburstNode value="#{row.WarehouseCount}" label="#{row.Country}"
                        id="sn4">
        <dvt:attributeGroups value="#{row.WarehouseCount}" type="color" id="ag4"/>
      </dvt:sunburstNode>
    </f:facet>
    <f:facet name="SRegionView12">
      <dvt:sunburstNode value="#{row.ProductCount}" label="#{row.City}" id="sn3">
        <dvt:attributeGroups value="#{row.ProductCount}" type="color" id="ag2"/>
      </dvt:sunburstNode>
    </f:facet>
    <f:facet name="SRegionView13">
      <dvt:sunburstNode value="#{row.AmountInStock}" label="#{row.Name}" id="sn2"
                        shortDesc="Amount in Stock: #{row.AmountInStock}&lt;br/>Reorder Point: #{row.ReorderPoint}">
        <dvt:attributeGroups value="#{row.AmountInStock}" type="color"
                             label="Amount in Stock" id="ag3">
          <dvt:attributeExceptionRule id="aer1" condition="#{(row.AmountInStock.value - row.ReorderPoint.value) gt 50}"
                                      label="Stock Level OK">
            <f:attribute name="color" value="#008800"/>
          </dvt:attributeExceptionRule>
          <dvt:attributeExceptionRule id="aer2"
                                      condition="#{((row.AmountInStock.value - row.ReorderPoint.value) le 50) and ((row.AmountInStock.value - row.ReorderPoint.value) gt 25)}"
                                      label="Stock Getting Low">
            <f:attribute name="color" value="#FFFF33"/>
          </dvt:attributeExceptionRule>
          <dvt:attributeExceptionRule id="aer3" condition="#{(row.AmountInStock.value - row.ReorderPoint.value) le 25}"
                                      label="Reorder Time">
            <f:attribute name="color" value="#880000"/>
          </dvt:attributeExceptionRule>
        </dvt:attributeGroups>
      </dvt:sunburstNode>
    </f:facet>
  </af:switcher>
</dvt:sunburst>

For information about configuring the sunburst or treemap level display, legendSource attribute, tooltips, additional attributes, or child tags, see the "Using ADF Treemap and Sunburst Components" chapter in the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

PK PKHwEOEBPS/web_adv.htm Creating More Complex Pages

28 Creating More Complex Pages

This chapter describes how to use ADF data binding to add more complex features to the pages of a Fusion web application. It describes how to use methods that take parameters for creating forms and command components. It also includes information about creating contextual events and using ADF Model-level validation.

This chapter includes the following sections:


Note:

Some of the implementation methods in this chapter are intended for page-level designs. If you are using task flows, you may be able to perform many of the same functions. For more information, see Chapter 14, "Getting Started with ADF Task Flows."


28.1 Introduction to More Complex Pages

Once you create a basic page and add navigation capabilities, you may want to add more complex features, such as passing parameters between pages or providing the ability to override declarative actions. Oracle ADF provides many features that allow you to add this complex functionality using very little actual code.

Some of the functions described in this chapter may be performed using other methodology. For example, if you are using task flows instead of individual page flows, you should use the task flow parameter passing mechanism. Or, if you are using ADF Business Components, you should use the validation rules on entity objects in the data model project, rather than using ADF Model validation rules. For more information about validation rules for Business Components, see Chapter 7, "Defining Validation and Business Rules Declaratively."

28.2 Creating Command Components to Execute Methods

When your application contains custom methods, these methods appear in the Data Controls panel. You can then drag these methods and drop them as command buttons. When a user clicks the button, the method is executed.

For more information about creating custom methods, see Section 9.7, "Customizing an Application Module with Service Methods," and Section 9.9, "Publishing Custom Service Methods to UI Clients."


Note:

If you are using task flows, you can call methods directly from the task flow definition. For more information, see Section 15.5, "Using Method Call Activities."


For example, the application module in the StoreFront module of the Fusion Order Demo application contains the updateItemInCart(Integer, Integer, Boolean) method. This method updates the items in the shopping cart. To allow the user to execute this method, you drag the updateItemInCart(Integer, Integer Boolean) method from the Data Controls panel, as shown in Figure 28-1.

Figure 28-1 Methods in the Data Controls Panel

Methods in Data Control panel

28.2.1 How to Create a Command Component Bound to a Custom Method

In order to perform the required business logic, many methods require a value for their parameter or parameters. This means that when you create a button bound to the method, you need to specify where the value for the parameter(s) is to be retrieved from.

Before you begin:

Create a custom method that can be added to the page.

For example, if you use the updateItemInCart(Integer, Integer, Boolean) method, you need to specify the items to be updated.

To add a button bound to a method:

  1. From the Data Controls panel, drag the method onto the page.


    Tip:

    If you are dropping a button for a method that needs to work with data in a table or form, that button must be dropped inside the table or form.


  2. From the context menu, choose Create > Methods > ADF Button.

    If the method takes parameters, the Edit Action Binding dialog opens. In the Edit Action Binding dialog, enter values for each parameter or click the Show EL Expression Builder menu selection in the Value column of Parameters to launch the EL Expression Builder.

28.2.2 What Happens When You Create Command Components Using a Method

When you drop a method as a command button, JDeveloper:

  • Defines a method action binding for the method.

  • If the method takes any parameters, JDeveloper creates NamedData elements that hold the parameter values.

  • Inserts code in the JSF page for the ADF Faces command component.

  • Binds the button to the method using actionListener.

  • Uses the return value from the method call.

28.2.2.1 Defining Method Action Binding

JDeveloper adds an action binding for the method. Action bindings use the RequiresUpdateModel property, which determines whether or not the model needs to be updated before the action is executed. For command operations, this property is set to true by default, which means that any changes made at the view layer must be moved to the model before the operation is executed.

28.2.2.2 Using Parameters in a Method

When you drop a method that takes parameters onto a JSF page, JDeveloper creates a method action binding. This binding is what causes the method to be executed when a user clicks the command component. When the method requires parameters to run, JDeveloper also creates NamedData elements for each parameter. These elements represent the parameters of the method.

For example, the updateItemInCart(Integer, Integer, Boolean) method action binding contains NamedData elements for the parameter. This element is bound to the value specified when you created the action binding. Example 28-1 shows the method action binding created when you drop the updateItemInCart(Integer, Integer, Boolean) method, and bind the Integer parameter (named productId) and the other Integer parameter (named quantity) and the Boolean parameter (named isSet) to the appropriate variables.

Example 28-1 Method Action Binding for a Parameter Method

<methodAction id="updateItemInCart"
                  InstanceName="StoreServiceAMDataControl.dataProvider"
                  DataControl="StoreServiceAMDataControl"
                  RequiresUpdateModel="true" Action="invokeMethod"
                  MethodName="updateItemInCart" IsViewObjectMethod="false">
      <NamedData NDName="productId" NDType="java.lang.Integer"/>
      <NamedData NDName="quantity" NDType="java.lang.Integer"/>
      <NamedData NDName="isSet" NDType="java.lang.Boolean"/>
</methodAction>

28.2.2.3 Adding ADF Faces Component Code to JSF Page

JDeveloper adds code for the ADF Faces component to the JSF page. This code is the same as code for any other command button, as described in Section 22.4.2.3, "EL Expressions Used to Bind to Navigation Operations." However, instead of being bound to the execute method of the action binding for a built-in operation, the button is bound to the execute method of the method action binding for the method that was dropped.

28.2.2.4 Using EL Expressions to Bind to Methods

Like creating command buttons using operations, when you create a command button using a method, JDeveloper binds the button to the method using the actionListener attribute. The button is bound to the execute property of the action binding for the given method using an EL expression. This EL expression causes the binding's method to be invoked on the application module. For more information about the command button's actionListener attribute, see Section 22.4.4, "What Happens at Runtime: How Action Events and Action Listeners Work."


Tip:

Instead of binding a button to the execute method on the action binding, you can bind the button to the method in a backing bean that overrides the execute method. Doing so allows you to add logic before or after the original method runs. For more information, see Section 28.4, "Overriding Declarative Methods."


Like navigation operations, the disabled property on the button uses an EL expression to determine whether or not to display the button. Example 28-2 shows the EL expression used to bind the command button to the updateItemInCart(Integer, Integer, Boolean) method.

Example 28-2 JSF Code to Bind a Command Button to a Method

<af:commandButton actionListener="#{bindings.updateItemInCart.execute}"
                          text="updateItemInCart"
                          disabled="#{!bindings.updateItemInCart.enabled}"/>

Tip:

When you drop a command button component onto the page, JDeveloper automatically gives it an ID based on the number of the same type of component that was previously dropped. For example, commandButton1, commandButton2. If you change the ID to something more descriptive, you must manually update any references to it in any EL expressions in the page.


28.2.2.5 Using the Return Value from a Method Call

You can also use the return value from a method call. Example 28-3 shows a custom method that returns a string value.

Example 28-3 Custom Method That Returns a Value

/**
 * Custom method.
*/
    public String getHelloString() {
        return ("Hello World");
    }

Example 28-4 shows the code in the JSF page for the command button and an outputText component.

Example 28-4 Command Button to Call the Custom Method

<af:commandButton actionListener="#{bindings.getHelloString.execute}"
        text="getHelloString"
        disabled="#{!bindings.getHelloString.enabled}"
        id="helloButtonId"/>
<af:outputText value="#{bindings.return.inputValue}"
        id="helloOutputId"/>

When the user clicks the command button, it calls the custom method. The method returns the string "Hello World" to be shown as the value of the outputText component.

28.2.3 What Happens at Runtime: Command Button Method Bindings

When the user clicks the button, the method binding causes the associated method to be invoked, passing in the value bound to the NamedData element as the parameter. For example, if a user clicks a button bound to the updateItemInCartItem(Integer, Integer, Boolean) method, the method takes the values of the product Id and quantity and updates the shopping cart.

28.3 Setting Parameter Values Using a Command Component

There may be cases where an action on one page needs to set parameters that will be used to determine application functionality. For example, you can create a search command button on one page that will navigate to a results table on another page. But the results table will display only if a parameter value is false.

You can use a managed bean to pass this parameter between the pages, and to contain the method that is used to check the value of this parameter. The managed bean is instantiated as the search page is rendered, and a method on the bean checks that parameter. If it is null (which it will be the first time the page is rendered), the bean sets the value to true.

For more information about creating custom methods, see Section 9.7, "Customizing an Application Module with Service Methods," and Section 9.9, "Publishing Custom Service Methods to UI Clients."


Note:

If you are using task flows, you can use the task flow parameter passing mechanism. For more information, see Chapter 16, "Using Parameters in Task Flows."


A setPropertyListener component with type property set to action, which is nested in the command button that executed this search, is then used to set this flag to false, thus causing the results table to display once the search is executed. For information about using managed beans, see Section 20.4, "Using a Managed Bean in a Fusion Web Application."

28.3.1 How to Set Parameters Using setPropertyListener Within a Command Component

You can use the setPropertyListener component to set values on other objects. This component must be a child of a command component.

Before you begin:

Create a command component on the page.

To use the setPropertyListener component:

  1. In the Component Palette, from the Operations panel, drag a setPropertyListener component and drop it as a child to the command component.

    Or right-click the component and select Insert inside Button > ADF Faces > setPropertyListener.

  2. In the Insert Set Property Listener dialog, enter the parameter value in the From field.

  3. Enter the parameter target in the To field.


    Tip:

    Consider storing the parameter value on a managed bean or in scope instead of setting it directly on the resulting page's page definition file. By setting it directly on the next page, you lose the ability to easily change navigation in the future. For more information, see Section 20.4, "Using a Managed Bean in a Fusion Web Application." Additionally, the data in a binding container is valid only during the request in which the container was prepared. The data may change between the time you set it and the time the next page is rendered.


  4. From the Type dropdown menu, select Action.

  5. Click OK.

28.3.2 What Happens When You Set Parameters

The setPropertyListener component lets the command component set a value before it navigates to the next page. When you set the from attribute either to the source of the value you need to pass or to the actual value, the component will be able to access that value. When you set the to attribute to a target, the command component is able to set the value on the target. Example 28-5 shows the code on the JSF page for a command component that takes the value false and sets it as the value of the initialSearch flag on the searchResults managed bean.

Example 28-5 JSF Page Code for a Command Button Using a setPropertyListener Component

<af:commandButton actionListener="#{bindings.Execute.execute}"
                 text=Search>
      <af:setPropertyListener from="#{false}"
                          to="#{searchResults.initialSearch}"/>
                          type="action"/>
</af:commandButton>

28.3.3 What Happens at Runtime: setPropertyListener for a Command Component

When a user clicks the command component, before navigation occurs, the setPropertyListener component sets the parameter value. In Example 28-5, the setPropertyListener takes the value false and sets it as the value for the initialSearchattribute on the searchResults managed bean. Now, any component that needs to know this value in determining whether or not to render can access it using the EL expression #{searchResults.initialSearch}.

28.4 Overriding Declarative Methods

When you drop an operation or method as a command button, JDeveloper binds the button to the execute method for the operation or method. However, there may be occasions when you need to add logic before or after the existing logic.


Note:

If you are using task flows, you can call custom methods from the task flow. For more information, see Chapter 14, "Getting Started with ADF Task Flows."


JDeveloper allows you to add logic to a declarative operation by creating a new method and property on a managed bean that provides access to the binding container. By default, this generated code executes the operation or method. You can then add logic before or after this code. JDeveloper automatically binds the command component to this new method, instead of to the execute property on the original operation or method. Now when the user clicks the button, the new method is executed.

For example, in the Fusion Order Demo application Orders page, the Commit operation requires additional processing. The Commit button is renamed to Submit Orders and logic is added to the submitOrders method in the orderPageBean managed bean.

In order to override a declarative method, you must have a managed bean to hold the new method to which the command component will be bound. If your page has a backing bean associated with it, JDeveloper adds the code needed to access the binding object to this backing bean. If your page does not have a backing bean, JDeveloper asks you to create one.

28.4.1 How to Override a Declarative Method

Before you begin:

Create the method that will override the declarative method in a managed bean. Operations are available by default.


Note:

You cannot override the declarative method if the command component currently has an EL expression as its value for the Action attribute, because JDeveloper will not overwrite an EL expression. You must remove this value before continuing.


To override a declarative method:

  1. Drag the operation or method to be overridden onto the JSF page and drop it as a UI command component.

    The component is created and bound to the associated binding object in the ADF Model layer with the ActionListener attribute.

    For more information about creating command components using methods on the Data Controls panel, see Section 28.2, "Creating Command Components to Execute Methods."

    For more information about creating command components from operations, see Section 22.4.2, "What Happens When You Create Command Buttons."

  2. On the JSF page, double-click the component.

  3. In the Bind Action Property dialog, identify the backing bean and the method to which you want to bind the component, using one of the following techniques:

    • If auto-binding has been enabled on the page, the backing bean is already selected for you, as shown in Figure 28-2.

      Figure 28-2 Bind Action Property Dialog for a Page with Auto-Binding Enabled

      Bind Action Property dialog for a page w/auto-binding
      • To create a new method, enter a name for the method in the Method field, which initially displays a default name.

        or

      • To use an existing method, select a method from the dropdown list in the Method field.

      • Select Generate ADF Binding Code.

    • If the page is not using auto-binding, you can select from an existing backing bean or create a new one, as shown in Figure 28-3.

      Figure 28-3 Bind Action Property Dialog for a Page with Auto-Binding Disabled

      Bind Action Property dialog.
      • Click New to create a new backing bean. In the Create Managed Bean dialog, name the bean and the class, and set the bean's scope.

        or

      • Select an existing backing bean and method from the dropdown lists.


    Note:

    Whenever there is a value for the ActionListener attribute on the command component, JDeveloper understands that the button is bound to the execute property of a binding. If you have removed that binding, you will not be given the choice to generate the ADF binding code. You will need to insert the code manually, or to set a dummy value for the ActionListener before double-clicking the command component.


  4. After identifying the backing bean and method, click OK in the Bind Action Property dialog

    JDeveloper opens the managed bean in the source editor. Example 28-6 shows the code inserted into the bean. In this example, a command button is bound to the Commit operation.

    Example 28-6 Generated Code in a Backing Bean to Access the Binding Object

    public String submitOrder() {
            BindingContainer bindings = getBindings();
            OperationBinding operationBinding =
                  bindings.getOperationBinding("Commit");
            Object result = operationBinding.execute();
            if (!operationBinding.getErrors().isEmpty()) {
                return null;
            }
    }
    
  5. You can now add logic either before or after the binding object is accessed, as shown in Example 28-7.

    Example 28-7 Code Added to the Overridden Method

    public String submitOrder() {
            DCBindingContainer bindings =
                (DCBindingContainer)JSFUtils.resolveExpression("#{bindings}");
            OperationBinding operationBinding =
                bindings.getOperationBinding("Commit");
            JUCtrlAttrsBinding statusCode =
                (JUCtrlAttrsBinding)bindings.findNamedObject("OrderStatusCode");
            statusCode.setAttribute("OrderStatusCode", "PENDING");
            JUCtrlAttrsBinding orderDate =
                (JUCtrlAttrsBinding)bindings.findNamedObject("OrderDate");
            orderDate.setAttribute("OrderDate", new Date());
            JUCtrlAttrsBinding orderId =
                (JUCtrlAttrsBinding)bindings.findNamedObject("OrderId");
            JSFUtils.storeOnSession("orderId", orderId.getAttribute("OrderId"));
            JUCtrlAttrsBinding invoiceTotal =
                (JUCtrlAttrsBinding)bindings.findNamedObject("InvoiceTotal");
            JUCtrlAttrsBinding orderTotal =
                (JUCtrlAttrsBinding)bindings.findNamedObject("OrderTotal");
            orderTotal.setAttribute("OrderTotal",
                 invoiceTotal.getAttribute("InvoiceTotal"));
            Object result = operationBinding.execute();
            ShoppingCartBean shoppingCartBean =
                 (ShoppingCartBean)JSFUtils.resolveExpression("#{shoppingCartBean}");
            shoppingCartBean.removeAllItems();
            return "orderSummary";
    }
    

    The code in Example 28-7 uses the FOD utility method JSFUtils.resolveExpression to resolve EL expressions. The code for such a method would be similar to the code in Example 28-8.

    Example 28-8 Utility Method to Solve EL Expressions

    public static Object resolveExpression(String expression) {
            FacesContext facesContext = getFacesContext();
            Application app = facesContext.getApplication();
            ExpressionFactory elFactory = app.getExpressionFactory();
            ELContext elContext = facesContext.getELContext();
            ValueExpression valueExp =
                elFactory.createValueExpression(elContext, expression, Object.class);
            return valueExp.getValue(elContext);
        }
    

    In addition to any processing logic, you may also want to write conditional logic to return one of multiple outcomes. For example, you might want to return null if there is an error in the processing, or another outcome value if the processing was successful. A return value of null causes the navigation handler to forgo evaluating navigation cases and to immediately redisplay the current page.


    Tip:

    To trigger a specific navigation case, the outcome value returned by the method must exactly match the outcome value in the navigation rule, including case.


    The command button is now bound to this new method using the Action attribute instead of the ActionListener attribute. If a value had previously existed for the Action attribute (such as an outcome string), that value is added as the return for the new method. If there was no value, the return is kept as null.

28.4.2 What Happens When You Override a Declarative Method

When you override a declarative method, JDeveloper adds a managed property to your backing bean with the managed property value of #{bindings} (the reference to the binding container), and it adds a strongly typed bean property to your class of the BindingContainer type, which the JSF runtime will then set with the value of the managed property expression #{bindings}. JDeveloper also adds logic to the UI command action method. This logic includes the strongly typed getBindings() method used to access the current binding container.

The code does the following:

  • Accesses the binding container.

  • Finds the binding for the associated method, and executes it.

  • Adds a return for the method that can be used for navigation. By default, the return is null. If an outcome string had previously existed for the button's Action attribute, that attribute is used as the return value. You can change this code as needed.

JDeveloper automatically rebinds the UI command component to the new method using the Action attribute, instead of the ActionListener attribute. Example 28-9 shows the code when a Commit operation is declaratively added to a page.

Example 28-9 JSF Page Code for a Command Button Bound to a Declarative Method

<af:commandButton actionListener="#{bindings.Commit.execute}"
                  text="Commit" 
                  disabled="#{!bindings.Commit.enabled}"/>

Example 28-10 shows the code after the method on the page's backing bean is overridden. Note that the action attribute is now bound to the backing bean's method.

Example 28-10 JSF Page Code for a Command Button Bound to an Overridden Method

<af:commandButton text="#{res['order.cart.submit']}"
           action="#{orderPageBean.submitOrder}"/>

Tip:

If when you click the button that uses the overridden method you receive this error:

SEVERE: Managed bean main_bean could not be created The scope of the referenced object: '#{bindings}' is shorter than the referring object

it is because the managed bean that contains the overriding method has a scope that is greater than request (that is, either session or application). Because the data in the binding container referenced in the method has a scope of request, the scope of this managed bean must be set to the same or a lesser scope.


28.5 Using the ADF Faces Calendar Component

ADF Faces includes a calendar component that displays created activities in daily, weekly, or monthly views. Figure 28-4 shows an ADF Faces calendar in weekly view mode with some sample activities.

Figure 28-4 ADF Faces Calendar

ADF Faces calendar component;

The calendar component also includes the following functionality:

Additionally, you can implement the following functionality using other ADF Faces components and the rich client framework:

Details for configuring the built-in functionality or for implementing additional functionality can be found in the "Creating a Calendar Application" chapter of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

An ADF Faces Calendar component must be bound to a CalendarModel class. This class can be created for you when you use ADF Business Components to manage your calendar's data. For example, say you have data in your data store that represents the details of an activity, such as the date, time, title, location, and owner. When you create an entity object to represent that data, and then a view object to display the data, you can drag and drop the associated collection from the Data Controls panel to create the calendar. JDeveloper will declaratively create the model and bind the view to that model so that the correct data will display when the calendar is launched. However, in order for the model to be created, your entity objects in the data model project with ADF Business Components and your view objects in the same project must contain date-effective attributes. Additionally, the view objects must contain variables that will be used to modify the query to return the correct activities for the given date range.

28.5.1 How to Use the ADF Faces Calendar

Before you can create a calendar on a JSF page, you must first create an entity object with specific attributes that represent attributes on a calendar. You then must create a view object from that entity object, and modify the query to use named bind variables that represent the date range and current time zone to display. This will allow the query to return only the activities that should be displayed in the given view on the calendar.

For example, say you have a database table that represents an activity. It has a column for title, start time, end time, and a reference to a provider object that represents the owner. You would create an entity object and a view object based on that table (ensuring that it meets the requirements, as described in the following steps). To the view object, you would then add named bind variables for the start and end times currently displayed on the calendar, along with the time zone currently in use by the calendar, so that the query returns only those activities that fall within that time range.

Once you add the calendar component to a JSF page, you can configure it, and add further needed functionality.

To create an ADF Faces calendar:

  1. Create an entity object based on your data source. The entity object must include the attributes shown in Table 28-1. The attributes do not have to use the names shown in the table; they can be named anything. However, they must be of one of the types noted. You will map these attributes to attributes in the CalendarModel in a later step.

    Table 28-1 Required Attributes for a Calendar

    AttributeValid TypesDescription

    Start time

    java.util.Date, java.sql.Date, oracle.jbo.domain.Date, oracle.jbo.domain.TimeStamp

    Start time for the activity

    End time

    java.util.Date, java.sql.Date, oracle.jbo.domain.Date, oracle.jbo.domain.TimeStamp

    End time for the activity

    ID

    String

    Unique ID

    Provider ID

    String

    ID of the provider object that represents the owner of the activity

    Title

    String

    Short description of the activity


    The entity object can also contain the known (but not required) attributes shown in Table 28-2:

    Table 28-2 Optional Attributes for a Calendar

    AttributeTypeDescription

    Recurring

    String or CalendarActivity.Recurring

    Status of recurrence for the activity. Valid values are SINGLE (does not recur), RECURRING, or CHANGED (this activity was part of the recurring activity but has been modified to be different from parent activity).

    Reminder

    String or CalendarActivity.Reminder

    Whether or not the activity has an associated reminder. Valid values are ON or OFF.

    Time Type

    String or CalendarActivity.TimeType

    Type of time associated with the activity. Valid values are ALLDAY and TIME. Activities that have a value of ALLDAY do not have any time associated with them. They are considered to span the entire day. Activities with a value of TIME have a specific time duration.

    Location

    String

    Location of an activity.

    Tags

    Set of Strings or a semicolon separated list of Strings.

    Keywords for the activity.


    Your entity objects can also contain other attributes that the CalendarModel has no knowledge of. You will be able to add these to the model as custom properties in a later step.

    For information on creating entity objects, see Chapter 4, "Creating a Business Domain Layer Using Entity Objects."

  2. Create an associated view object. In the Query page of the overview editor, create named bind variables for the following:

    • A string that represents the time zone

    • A date that represents the start time for the current date range shown on the calendar.

    • A date that represents the end time for the current date range shown on the calendar.


      Tip:

      Dates in an ADF Faces calendar are "half-open," meaning that the calendar will return all activities that start on or after the start time and before (but not on) the end time.


      For more information about creating named bind variables, see Section 5.10, "Working with Bind Variables".

  3. Create an entity object that represents the provider (owner) of activities. The entity object must include the attributes shown in Table 28-3. The attributes do not have to use the names shown in the table; they can be named anything. However, they must be of the type noted. You will map these attributes to attributes in the CalendarProvider class in a later step.

    Table 28-3 Attributes for a CalendarProvider Class

    AttributeTypeDescription

    Id

    String

    Unique ID.

    Display Name

    String

    The name of the provider that can be displayed in the calendar.


  4. Create a view object for the provider.

  5. Ensure that the new view objects are part of the application module, and if needed, refresh the Data Controls panel.

  6. Create your JSF page, as documented in Section 20.3, "Creating a Web Page".

  7. From the Data Controls panel, drag the collection that represents the view object for the activity created in Step 2 and drop it as a Calendar.


    Tip:

    The Calendar option will display in the context menu only if the view object contains the required attributes documented in Table 28-1 and the bind variables described in Step 2.


  8. Complete the Calendar Bindings dialog to map the bind variables and attributes to the CalendarModel and the CalendarProvider classes. For additional help, click Help or press F1.

  9. By default, the calendar will be read-only and will return only those activities currently in the data store. You will need to configure the calendar and implement additional functionality as described in the "Creating a Calendar Application" chapter of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

    For example, to allow creation of a new activity, you might create an input form in a dialog (as described in the "How to Create a Dialog" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework) using the same data control collection used to create the calendar. For more information about creating input forms, see Section 22.6, "Creating an Input Form".

28.5.2 What Happens When You Create a Calendar

When you drop a collection as a calendar, JDeveloper:

  • Defines an iterator binding to the collection of activities, and another iterator binding to the collection of providers.

  • Defines an action binding to the executeWithParams operation on the activities collection. It is this operation that will be invoked to execute the query to return the activities to display. Because the operation requires parameters to determine the date range and time zone, NamedData elements are also created for each of the parameters (created as named bind variables on the view object). For more information about NamedData elements, see Section 28.2.2.2, "Using Parameters in a Method".

  • Defines a calendar binding. This binding contains a node element that represents a row in the collection and maps the data control attributes to the calendar activity's attributes, as defined when using the wizard.The value is the data control attribute and the type is the calendar attribute. For any custom defined attributes, the type will be custom and value will be the data control attribute. Each row (node) is represented by a rowKey, which is the activity ID.

    There is also a providerDefinition element the determines the source and mapping of available providers. This mapping allows the calendar model to filter activities based on the state of the provider (either enabled or disabled).


    Tip:

    To access a custom attribute, use the CalendarActivity.getCustomAttributes() method, passing in the name of the attribute as defined by the value element.


    Example 28-11 shows the page definition code for a calendar.

Example 28-11 Page Definition Code for a Calendar Binding

<executables>
    <iterator Binds="ActivityView1" RangeSize="-1"
              DataControl="AppModuleDataControl" id="ActivityView1Iterator"/>
    <iterator Binds="EmployeesView1" RangeSize="25"
              DataControl="AppModuleDataControl" id="EmployeesView1Iterator"/>
  </executables>
  <bindings>
    <action IterBinding="ActivityView1Iterator" id="ExecuteWithParams"
            RequiresUpdateModel="true" Action="executeWithParams">
      <NamedData NDName="startTime"
                 NDValue="#{bindings.ActivityView1.startDate}"
                 NDType="oracle.jbo.domain.Date"/>
      <NamedData NDName="endTime" NDValue="#{bindings.ActivityView1.endDate}"
                 NDType="oracle.jbo.domain.Date"/>
      <NamedData NDName="timeZone"
                 NDValue="#{bindings.ActivityView1.timeZoneId}"
                 NDType="java.lang.String"/>
    </action>
    <calendar IterBinding="ActivityView1Iterator" id="ActivityView1"
              xmlns="http://xmlns.oracle.com/adf/faces/binding"
              ActionBindingName="ExecuteWithParams">
      <nodeDefinition DefName="model.ActivityView">
        <AttrNames>
          <Item Type="id" Value="Id"/>
          <Item Type="providerId" Value="ProviderId"/>
          <Item Type="title" Value="Title"/>
          <Item Type="startTime" Value="StartTime"/>
          <Item Type="endTime" Value="EndTime"/>
        </AttrNames>
      </nodeDefinition>
      <providerDefinition IterBindingName="EmployeesView1Iterator">
        <AttrNames>
          <Item Type="id" Value="EmployeeId"/>
          <Item Type="displayName" Value="FirstName"/>
        </AttrNames>
      </providerDefinition>
    </calendar>
  </bindings>

JDeveloper inserts code onto the JSF page that binds the calendar value to the CalendarModel class, as shown in Example 28-12.

Example 28-12 JSF Page Code for a Calendar

<af:form>
  <af:calendar value="#{bindings.ActivityView1.calendarModel}"/>
</af:form>

The CalendarModel class uses CalendarActivityDefinition class to access the calendar binding.

28.5.3 What Happens at Runtime: How the Calendar Binding Works

When the calendar is accessed, the executeWithParams operation is invoked, with the value of the startDate and endDate parameters determined by the value of the calendar component's view and activeDay attributes. For example, if the view attribute is set to month and the activeDay is set to the current date (say, February 6, 2009), then the value for the startDate would be February 1, 2009 and the endDate value would be February 28, 2009. By default, the time zone value is taken from the time-zone setting in the trinidad-config.xml file (for more information, see the "Configuration in trinidad-config.xml" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework). Therefore, the query would be restricted to return only activities that fall within that date range.

When the query returns data, because the calendar component is bound to the CalendarModel, the CalendarModel uses the CalendarActivityDefinition class to access the calendar binding class and map the values from the data source to the calendar, using the mappings provided by the binding.

28.6 Using the ADF Faces Carousel Component

You can display images in a revolving carousel, as shown in Figure 28-6. Users can change the image at the front by using either the slider at the bottom or by dragging another image to the front.

Figure 28-6 Carousel Component

Carousel component.

Instead of containing a child carouselItem component for each image to be displayed, and then binding these components to the individual images, the carousel component is bound to a complete collection and repeatedly renders one carouselItem component by stamping the value for each item, similar to the way a tree stamps out each row of data. As each item is stamped, the data for the current item is copied into a property that can be addressed using an EL expression using the carousel component's var attribute. Once the carousel has completed rendering, this property is removed or reverted back to its previous value. Carousels contain a nodeStamp facet, which is a holder for the carouselItem component used to display the text and short description for each item, and is also the parent component to the image displayed for each item. For more information about the carousel component, see the "Displaying Images in a Carousel" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

28.6.1 How to Create a Databound Carousel Component

When using a carousel component in a Fusion web application, you create the component using the Data Controls Panel. You also use a managed bean to handle the carousel spin event, and for other logic you may need to display your items.

Before you begin:

You need to create a view object for the collection to be displayed in the carousel. The view object should contain attributes for at least the following:

  • Title, which will be displayed below the image in the carousel

  • Short description used for text displayed when the user mouses over the image.

To create a databound carousel component:

  1. From the Data Controls panel, drag the collection for the view object on to the page and select Carousel from the context menu.

  2. In the Property Inspector, in the Behavior section, bind the CarouselSpinListener to a handler method that handles the spinning of the carousel when you need logic to be executed when the carousel spin is executed. Example 28-13 shows the handler methods that might be used to handle the display of product images for the Products view object used to create the carousel:

    Example 28-13 Handler for the CarouselSpinEvent

    public void handleCarouselSpin(CarouselSpinEvent event)
    {
      RichCarousel carousel = getCarousel();
      carousel.setRowKey(event.getNewItemKey());
      detailNodeItem = (JUCtrlHierNodeBinding)carousel.getRowData();
    }
    public JUCtrlHierNodeBinding getDetailNodeItem()
    {
    //   Get the initial item
      if(detailNodeItem == null)
      {
        RichCarousel carousel = getCarousel();
        
        Object oldKey = carousel.getRowKey();
        try
          {
             Object key = carousel.getCurrentItemKey();
              getCarousel().setRowKey(key);
              detailNodeItem = (JUCtrlHierNodeBinding)carousel.getRowData();
           }
        finally
         {
           carousel.setRowKey(oldKey);
          }
        }
         
      return detailNodeItem;
    }
       
    
  3. In the Advanced section of the Property Inspector, click the dropdown menu for the Bindings attribute and select Edit. In the Edit Property: Binding dialog, select the managed bean used in Step 2. Create a new property called carousel. This will allow the handler methods to access the carousel object.

  4. In the Structure window, expand the carousel component and the nodeStamp facet, and select the carouselItem component.

  5. Bind the CarouselItem component's text attribute to the associated property in the data model using variable value set on the carousel's var attribute, which by default is set to item. So the value of the carouselItem's text attribute would be item.title (given that title is the property used to access the text used for the carousel items on the data model).

    If you were using the Products view object, the value would be #{item.ProductName}.

  6. In the Advanced section of the Property Inspector, click the dropdown menu for the Bindings attribute and select Edit. In the Edit Property: Binding dialog, select the managed bean used in Step 2. Create a new property called carouselItem.

  7. In the ADF Faces page of the Component Palette, from the Common Components panel, drag an Image and drop it as a child to the carouselItem.

    In the Insert Image dialog, enter the path to the source for the images, being sure to use the variable for the item in the carousel. For example, the path to the image files for the products would normally be:

    /imageservlet?detail=#{Products.ProductId}
    

    For an image in the carousel, you would use:

    /imageservlet?detail=#{item.ProductId}
    

    For information about setting other attributes of the carousel and carouselItem components, see the "How to Create a Carousel" section of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

  8. If you want to provide additional information about the items in the carousel, you can drag and drop the same view object onto the page, for example, as a form. For the components in the form to redisplay the information for the current item displayed once the carousel is spun, you need to set the partialTrigger attribute of the component containing the form to the carousel component's ID.

    For example, the form that displays the information for each item in Figure 28-6 is contained in a panelBox component.The partialTrigger attribute for the panelBox component is set to c1, which is the carousel component's ID. This means that whenever the carouselItem invokes the CarouselSpinEvent, the panelBox will be refreshed, causing it to display information about the item that was just made current. For more information about partial page rendering and the partialTriggers attribute, see the "Rendering Partial Page Content" chapter of the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework.

    Example 28-14 shows the page code for the carousel displayed in Figure 28-6.

    Example 28-14 Partial Trigger Updates the Form to Match the Displayed Carousel Item

    <af:carousel
            currentItemKey="#{bindings.Products.treeModel.rootCurrencyRowKey}"
      value="#{bindings.Products.treeModel}" var="item"
      id="c1"
     carouselSpinListener="#{carBean.handleCarouselSpin}">
       <f:facet name="nodeStamp">
         <af:carouselItem id="ci1" text="#{item.ProductName}"
                          binding="#{carBean.carouselItem}">
           <af:image source="/imageservlet?detail=#{item.ProductId}"
                     id="i1"/>
         </af:carouselItem>
       </f:facet>
     </af:carousel>
     <af:panelBox text="PanelBox1" id="pb1" partialTriggers="c1">
       <af:panelFormLayout id="pfl1">
         <af:panelLabelAndMessage label="#{bindings.ProductName.hints.label}"
                                  id="plam2">
           <af:outputText value="#{bindings.ProductName.inputValue}"
                          id="ot4"/>
         </af:panelLabelAndMessage>
    .
    .
    .
    </af:panelBox>
    

28.6.2 What Happens When You Create a Carousel

When you drop a collection from the Data Controls panel as a carousel, a tree value binding is created. A tree consists of a hierarchy of nodes, where each subnode is a branch off a higher level node.

The tree binding iterates over the data exposed by the iterator binding. The carousel wraps the result set from the iterator binding in a treeModel object, which is an extension of the collectionModel. The collectionModel allows each item in the collection to be available within the carousel component using the var attribute. For more information about the tree binding, see Section 23.2.2.1, "Iterator and Value Bindings for Tables."

JDeveloper adds both a carousel component and it's child carouselItem component onto the page, as shown in Example 28-15.

Example 28-15 Page Code for a Carousel Component

<af:carousel
        currentItemKey="#{bindings.Products.treeModel.rootCurrencyRowKey}"
        value="#{bindings.Products.treeModel}" var="item"
        id="c1"
        carouselSpinListener="#{carBean.handleCarouselSpin}">
   <f:facet name="nodeStamp">
     <af:carouselItem id="ci1" text="#{item.ProductName}"/>
   </f:facet>
 </af:carousel>

The carousel value is bound to the treeModel for the associated collection, and the currentItemKey attribute of the carousel is bound to the rootCurrencyRowKey of the binding object. In this example, the carousel iterates over the items in the Products iterator binding. The iterator binding binds to a rowKeySet that keeps track of the current product. By default, the currentItemKey attribute of the carousel is bound to the rootCurrencyRowKey of the binding object, which causes the product currently displayed at the front of the carousel to be the root and the current item. The carouselItem component accesses the current data object for the current item presented to the carousel tag using the item variable.

28.7 Creating Contextual Events

Often a page or a region within a page needs information from somewhere else on the page or from a different region. While you can pass parameters to obtain that information, doing so makes sense only when the parameters are well known and the inputs are EL-accessible to the page. Parameters are also useful when a task flow may need to be restarted if the parameter value changes.

However, suppose you have a task flow with multiple page fragments that contain various interesting values that could be used as input on one of the pages in the flow. If you were to use parameters to pass the value, the task flow would need to surface output parameters for the union of each of the interesting values on each and every fragment. Instead, for each fragment that contains the needed information, you can define a contextual event that will be raised when the page is submitted. The page or fragment that requires the information can then subscribe to the various events and receive the information through the event.

For example, in the StoreFront module, contextual events are used in the customer registration page to display the appropriate informational topic. The user registration page register.jspx contains two regions. One region contains the customer registration task flow customer-registration-task-flow, and the other contains the informational topic task flow help-task-flow. A contextual event is passed from the customer registration region to the informational topic region so that the informational topic task flow can display the information topic. At design time, the event name, producer region, consumer region, consumer handler, and other information is stored in the event map section of the page definition file, as shown in Example 28-16.

Example 28-16 Event Map in the registerPageDef.xml File

<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
    <event name="queueHelpTopic">
      <producer region="*">
        <consumer region="helptaskflow1"
                  handler="helpPageDef.findHelpTextById">
         <parameters>
            <parameter name="helpTopicId" value="${payLoad}"/>
          </parameters> 
        </consumer>
      </producer> 
    </event>
</eventMap>

At runtime, when a user enters the customer registration task flow, he or she progresses through a series of view activities from Basic Information to Address and then to Payment Options by entering data and clicking the Next button. When the user clicks Next, a contextual event with a payLoad parameter is broadcasted by the customer registration task flow. This event is then consumed by the information task flow and its handler, the helpPageDef.findHelpTextById() method. The consuming method uses the payLoad parameter to determine which information topic text to display. In the event map, you can specify EL expressions to bind the input parameters to variables and parameters of the page.

Events are configured in the page definition file for the page or region that will raise the event (the producer). In order to associate the producer with the consumer that will do something based on the event, you create an event map also in the page definition (when using events between regions, the page definition file which holds both the regions contains the event map). If the consuming page is in a dynamic region, the event map should be in the page definition file of the consuming page and the producer's attribute region set to "*". The attribute region is set to "*" because at design time, the framework cannot determine the relative path to the producer.

You can raise a contextual event for an action binding, a method action binding, a value attribute binding, or a range binding (table, tree, or list binding). You also can conditionally fire an event and conditionally handle an event using EL expressions.

For action and method action bindings, the event is raised when the action or method is executed. The payLoad contains the binding container and event source, and a single parameter that you can define. Action bindings can be published by multiple sources, while value attribute and list bindings can be published only by a single source.

You can also raise a contextual event from an ADF Faces event such as clicking a button or selecting from a menu. The ADF Faces component will use eventBinding to act as a contextual event producer.

For a value attribute binding, the event is triggered by the binding container and raised after the attribute is set successfully. The payLoad contains the new value, iterator, binding container and source object, and a single parameter that you can define. Example 28-17 shows a value change event inside an attribute value binding associated with an input component. The event, valueChangeEvent, will be dispatched when the user changes the value of LAST_NAME in the page.

Example 28-17 Value Attribute Event in the Page Definition File

<attributeValues IterBinding="DeptView1Iterator" id="Dname"
     xmlns="http://xmlns.oracle.com/adfm/jcuimodel">
    <events xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
        <event name="valueChangeEvent"/>
     </events>                     
     <AttrNames xmlns="http://xmlns.oracle.com/adfm/uimodel">
        <Item Value="LAST_NAME"/>
      </AttrNames>
</attributeValues>
</bindings>
<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
    <event name="valueChangeEvent">
      <producer region="LAST_NAME">
        <consumer region="" handler="consumeEvent"/>
      </producer>
    </event>
</eventMap>

For a range binding (tree, table, list), the event is raised after the currency change has succeeded. The payLoad contains the iterator, row key, binding container and source object, and a single parameter you can define.

Value attribute binding and range binding contextual events may also be triggered by navigational changes. For example, if you create an event inside a tree table binding, the event will be dispatched when the user selects a different node of the tree in the page.

You create, publish, and subscribe to contextual events using the overview editor for page definition file's Contextual Events tab, as shown in Figure 28-7.

Figure 28-7 Page Definition Contextual Events Tab

Page Definition Contextual Events Tab

You can also use the Contextual Events page in the Property Inspector to create, publish, and subscribe to contextual events. The Contextual Events panel will only appear when you select eligible components in the page, as shown in Figure 28-8.

Figure 28-8 Contextual Events Panel in the Property Inspector

Property Inspector for Contextual Events

Contextual events are not the same as the business events that can be raised by ADF Business Components or the events raised by UI components. For a description of these types of events, see the Oracle Fusion Middleware Web User Interface Developer's Guide for Oracle Application Development Framework. Contextual events can be used in, however, in association with UI events. In this case, an action listener that is invoked due to a UI event can, in turn, invoke a method action binding that then raises the event.

28.7.1 How to Create Contextual Events Declaratively

You create contextual events by first creating and publishing the event on the producer based on an action, method action, value attribute, or list binding. On the consumer, you subscribe to the event and create a handler to process the event.


Note:

You can also publish an action contextual event from code (for example, from within a managed bean), using the call:

getBindingContainer.raiseEvent(myEventName);

Before you begin:

Decide on the type of component you want to use to raise the contextual event. If you plan to use a method action binding, you must have already created the method to be dropped onto the page.

Typically, you create a parent page with regions that contain task flows and view activities. You create contextual events in one region to be published for consumer event handlers in the other region. For more information about using task flows and regions, see Chapter 17, "Using Task Flows as Regions."

28.7.1.1 Creating Contextual Events in the Publisher

You use the overview editor for page definition files to create contextual events in the producer's page.

To create a contextual event:

  1. In the producer page, drag and drop a component from the Data Controls panel to the page that will trigger the event. It must have an action, method action, value attribute, or list binding. In the StoreFront module, the setHelpId() method from the Data Controls panel was added to the page.

  2. In the overview editor for the producer page definition, select the Contextual Events tab.

  3. In the Events section, click the Add icon.

  4. In the Publish Contextual Events dialog:

    1. Select Create New Event.

    2. Enter the name of the event.

    3. Select Pass Custom Value From if you want to pass payLoad data to the consumer.

    4. If you are passing payload data, select the type of data from the dropdown list.

      For example, if you want to pass an attribute value from the producer page to the consumer page, you can select Page Data and select the attribute from the tree structure.

    5. You can conditionally raise the event by entering an EL expression in the Raise Condition tab.

      For instance, entering an expression such as ${bindings.LAST_NAME.inputValue == 'KING'} will cause the event to be raised only if the customer's last name is KING.

    6. Click OK.

      The event is created on the page, but it is not ready for publishing until it is associated with the component binding.

      Figure 28-9 Publish a Contextual Event

      Publish a Contextual Event
  5. In the producer page, select the component you want to trigger the event, open the Contextual Events pane in the Property Inspector, and click the Add icon

  6. In the Publish Contextual Events dialog:

    1. Choose Select Existing Event.

    2. Click the Search icon next to the Name field.

    3. In the Select Contextual Event dialog, select the event from the tree structure. The event should be the one you have created in Step 4.

    4. Click OK and click OK again.

      The event is now ready for publishing.

  7. Alternatively, you can create and enable publishing an event in one gesture by accessing the Publish Contextual Events dialog via the Property Inspector for the component when you add the component to the page as described in Step 1. Creating the event in the page definition makes it available for components on that page to publish the event and for other pages to subscribe to that event.

28.7.1.2 Subscribing to and Consuming Events

You use the overview editor for page definition files on the parent page to subscribe to contextual events.

To subscribe and consume the event:

  1. In the consuming page, add the components that may respond to the event.

    In the StoreFront module, the findHelpTextById method handler return String is dropped onto the page as an outputText component to display the help information.

  2. Create a handler to process the event and its payLoad data. In the StoreFrontModule example, the findHelpTextById handler method was created in the LookupServiceAMDataControl module. You can add an EL expression to the handler to conditionally handle the page.

  3. In the overview editor for the consumer page definition's Bindings and Executables tab, click the Add icon in the Bindings section.

  4. In the Insert Item dialog, select methodAction and click OK.

  5. In the Create Action Binding dialog:

    1. Select the data collection where you have created your handler.

    2. From the Operation dropdown list, select the handler.

    3. Click OK.

  6. In the overview editor for the consumer page definition's Bindings and Executables tab, Click the Add icon in the Bindings section.

  7. In the Insert Item dialog, select attributeValue and click OK.

  8. In the Create Attribute Binding dialog:

    1. From the Data Source dropdown list, select Variable.

    2. Select the return value of the handler as the Attribute.

    3. Click OK.

  9. In the overview editor of the parent page definition (where both regions are located), navigate to the Contextual Events tab, and from the Events section click the Add icon.

  10. In the Publish Contextual Events dialog, select Select Existing Event and click the Search icon.

  11. In the Select Contextual Events dialog, select the event you want to publish from the tree and click OK.

  12. In the Publish Contextual Events dialog, check the event parameters and click OK.

    The event appears in the Events list in the overview editor for page definition file.

  13. In the overview editor of the parent page definition, click Subscribers and click the Add icon in the Event Subscribers section.

  14. In the Subscribe to Contextual Event dialog, click the Search icon.

  15. In the Select Contextual Events dialog, select the event you want to subscribe to from the tree and click OK.

  16. In the Subscribe to Contextual Event dialog:

    1. Select the producer or <Any> from the Publisher dropdown list. A contextual event can have more than one publisher.

      Selecting <Any> will allow the consumer to subscribe to any event. In the page definition file, the producer attribute will be set to the wildcard "*". If your publisher is in a dynamic region, you should set this field to <Any> so that the subscriber can consume from any producer.

    2. Click the Search icon next to the Handler field.

    3. In the Select Handler dialog, select the event handler from the tree and click OK.

    4. If the handler requires parameters, select the Parameters tab, click Add, and enter name-value pair as parameters.

    5. If you want to conditionally handle the event, select the Handle tab, and enter an EL Expression that determines the conditions under which the handler will process the event.

    6. Click OK.

    Figure 28-10 Subscribe to a Contextual Event

    Subscribe to a Contextual Event

Note:

You can edit the event map by right-clicking the page definition in the Structure window and choosing Edit Event Map. You can also edit event attributes in the page definition file or in the Property Inspector.


28.7.2 How to Create Contextual Events Manually

You create contextual events by first creating the event on the producer. You then determine the consumer of the event and map the producer and consumer.

Before you begin:

Create a contextual event that has a method binding, action binding, value attribute binding, or list binding on the producer page. If you do not, you must create the binding first. For example, for a method binding, in the Structure window, right-click the binding and choose Insert inside bindings > Generic Bindings > methodAction and add the method action binding or use the overview editor for the page definition file to add the binding. For the other bindings, you may need to drop a component such as an input text, table, or tree to the page.

To create a contextual event:

  1. Open the page definition file that contains the binding for the producer of the event.

    A producer must have an associated binding that will be used to raise the event. For example, if a method or operation will be the producer, the associated action binding or method action binding will contain the event.

  2. In the Structure window, right-click the binding for the producer and choose Insert inside binding name > events or Insert inside binding name > Contextual Events > events.

  3. In the Structure window, right-click the events element just created, and choose Insert inside events > event.

  4. In the Insert event dialog, enter a name for the event in the name field, and click Finish.

    The event is now created. By default, any return of the associated method or operation will be taken as the payload for the event and stored in the EL-accessible variable ${payLoad}. You now need to map the event to the consumer, and to configure any payload that needs to be passed to the consumer.

  5. Open the page definition that contains the binding for the consumer.

    The binding container represented by this page provides access to the events from the current scope, including all contained binding containers (such as task flow regions). If regions or other nested containers need to be aware of the event, the event map should be in the page definition of the page in the consuming region.

  6. In the Structure window, right-click the topmost node that represents the page definition, and choose Edit Event Map.


    Note:

    If the producer event comes from a page in an embedded dynamic region, you may not be able to edit the event map using the Event Map Editor. You can manually create the event map by editing the page definition file or use insert inside steps, as described in Section 28.7.5, "How to Manually Create the Event Map."


  7. In the Event Map Editor, click the Add icon to add an event entry.

  8. In the Add New EventMap Entry dialog, do the following:

    1. Use the Producer dropdown menu to choose the producer.

    2. Use the Event Name dropdown menu to choose the event.

    3. Use the Consumer dropdown menu to choose the consumer. This should be the actual method that will consume the event.

    4. If the consuming method or operation requires parameters, click the Add icon.

      In the Param Name field, enter the name of the parameter expected by the method. In the Param Value field, enter the value. If this is to be the payload from the event, you can access this value using the ${payLoad} expression. If the payload contains many parameters and you don't need them all, use the ellipses button to open the Expression Builder dialog. You can use this dialog to select specific parameters under the payload node.

      You can also click the Parameters ellipses button to launch the selection dialog.

    5. Click OK.

  9. In the Event Map Editor, click OK.

28.7.3 How to Create Contextual Event Using Managed Beans

You can publish an action contextual event from code such as from within a managed bean. You bind the producer component to the method in the managed bean, as shown in Example 28-18.

In this example, the producer is a command button that invokes an action binding and the consumer is an outputText component that displays a string. They are both on the same page.

Example 28-18 Event Producer and Event Consumer on the JSF

<af:form id="f1">
     <af:eventProducerButton value="eventProducerButton1" id="cb1"
                         action="#{MyBean.myActionPerformed}"
                         />
     <af:panelLabelAndMessage label="#{bindings.return.hints.label}"id="plam1">
          <af:outputText value="#{bindings.return.inputValue}" id="ot1"/>
     </af:panelLabelAndMessage>
</af:form>

The page definition file contains the method action bindings for the producer, the consumer, and the event map, as shown in Example 28-19.

Example 28-19 Page Definition with Event Producer, Event Consumer, and Event Map

<executables>
    <variableIterator id="variables">
      <variable Type="java.lang.String" Name="eventConsumer_return"
                IsQueriable="false" IsUpdateable="0"
                DefaultValue="${bindings.eventConsumer.result}"/>
    </variableIterator>
</executables>
<bindings>
     <methodAction id="eventProducer"
                  InstanceName="AppModuleDataControl.dataProvider"
                  DataControl="AppModuleDataControl" RequiresUpdateModel="true"
                  Action="invokeMethod" MethodName="eventProducer"
                  IsViewObjectMethod="false"
                  ReturnName="AppModuleDataControl.methodResults.eventProducer_
                       AppModuleDataControl_dataProvider_eventProducer_result">
            <events xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
                  <event name="myEvent"/>
            </events>
     </methodAction>
     <methodAction id="eventConsumer" RequiresUpdateModel="true"
                  Action="invokeMethod" MethodName="eventConsumer"
                  IsViewObjectMethod="false" DataControl="AppModuleDataControl"
                  InstanceName="AppModuleDataControl.dataProvider"
                  ReturnName="AppModuleDataControl.methodResults.eventConsumer_
                        AppModuleDataControl_dataProvider_eventConsumer_result">
               <NamedData NDName="str" NDValue="test" NDType="java.lang.String"/>
    </methodAction>
    <attributeValues IterBinding="variables" id="return">
        <AttrNames>
             <Item Value="eventConsumer_return"/>
        </AttrNames>
    </attributeValues>
</bindings>
<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
    <event name="myEvent">
      <producer region="eventProducer">
        <consumer region="" handler="eventConsumer">
          <parameters>
            <parameter name="test" value="${payLoad}"/>
          </parameters>        
        </consumer>
      </producer>
    </event>
</eventMap>

In the managed bean, create a method for the producer method action binding. This method will include code to publish the contextual event. Example 28-20 show the myBean managed bean and the myActionPerformed method that creates the eventProducer contextual event.

Example 28-20 Managed Bean Code to Generate Contextual Events

public class myBean {
    public myBean() {
    }

public Object myActionPerformed() {
        // Add event code here...
        BindingContainer bc BindingContext.getCurrent().getCurrentBindingsEntry();
        JUCtrlActionBinding actionBnd =
                 (JUCtrlActionBinding)bc.getControlBinding("eventProducer");

        ((DCBindingContainer)bc).getEventDispatcher().queueEvent(actionBnd.
                 getEventProducer(),"myString");

        ((DCBindingContainer)bc).getEventDispatcher().processContextualEvents();
                 return null;
    }
}

When the button is pressed, the myActionPerformed method is invoked and calls the following methods to generate the contextual event:

        ((DCBindingContainer)bc).getEventDispatcher().queueEvent(actionBnd.
                 getEventProducer(),"myString");
        ((DCBindingContainer)bc).getEventDispatcher().processContextualEvents();
                 return null;

28.7.4 How to Create a Contextual Event from JavaScript

Every action and method binding that is accessible from a managed bean can be invoked from JavaScript. ADF Faces provides an af:serverListener operation component that can be used to call a managed bean method from client-side JavaScript. To invoke this component using the referenced managed bean method, use the BindingContext object to look up the current BindingContainer and to access the OperationBinding or a JUEventBinding binding. The af:serverListener component can also be used to send a message payload from the browser client to the managed bean method.

28.7.5 How to Manually Create the Event Map

Under most circumstances, you can create the event map using the Event Map Editor as described in Section 28.7.2, "How to Create Contextual Events Manually." However, in situations such as when the producer event is from a page in an embedded dynamic region, the Event Map Editor at design time cannot obtain the necessary information to create an event map.

To create the event map manually:

  1. Open the page definition that contains the binding for the consumer.

  2. In the Structure window, right-click the topmost node that represents the page definition, and choose Insert inside pagedef name > eventMap.

    An eventMap node appears in the Structure window.

  3. Select the eventMap node, right-click and choose Insert inside eventMap > event.

    In the Insert Event dialog, enter the name of the event and click OK.

    An event node appears under the eventMap node.

    Repeat this step to add more events.

  4. Select event, right-click and choose Insert inside event > producer.

    The Insert Producer dialog appears. Enter the name of the binding that is producing this event. You can also enter the name of the producer region, in which case all the consumers specified under this tag can consume the event. You can also enter "*" to denote that this event is available for all consumers under this tag. Click OK.

    A producer node appears under the event node.

  5. Select producer, right-click and choose Insert inside producer > consumer.

    The Insert Consumer dialog appears. Enter the name of the handler that will consume the event. Click OK.

    A consumer node appears under the producer node.

    Repeat this step to add more consumers.

  6. If there are parameters being passed, add the parameter name and value. Select consumer, right-click and choose Insert inside consumer > parameters.

    A parameters node appears under the consumer node.

    Select parameters, right-click and choose Insert inside parameters > parameter.

    The Insert parameter dialog appears. Enter the name of the parameter and the value of the parameter. The value can be an EL expression. Click OK.

    Repeat Insert inside parameters > parameter to add more parameters

28.7.6 How to Register a Custom Event Dispatcher

By default, the contextual event framework uses EventDispatcherImpl to dispatch events that would traverse through the regions. You can create a custom event dispatcher to override the default event dispatcher to provide custom behaviors. After you have created the custom event dispatcher, you must register it in the Databindings.cpx file to override the default dispatcher.

To register a custom event dispatcher:

  1. Create a custom event dispatcher Java class based on the EventDispatcher class.

  2. Register the custom event dispatcher in the Databindings.cpx file with a fully qualified name using the following format:

    EventDispatcher="package_name.CustomEventDispatcher_name"
    

    Example 28-21 shows the code for a custom event dispatcher called NewCustomEventDispatcher created in package NewPackage.

    Example 28-21 Adding Custom Event Dispatcher in the Databindings.cpx File

    <Application xmlns="http://xmlns.oracle.com/adfm/application"
                 version="11.1.1.51.60" id="DataBindings" SeparateXMLFiles="false"
                 Package="project3" ClientType="JClient"
                 EventDispatcher="NewPackage.NewCustomEventDispatcher">
    
  3. Create the event in the producer's page definition.

  4. Create the event map in the consumer region if the consumer is in a dynamic region. If the consumer is not in a dynamic region, you can also specify the event map in the parent page which holds both the producer and consumer regions.

28.7.7 What Happens When You Create Contextual Events

When you create an event for the producer, JDeveloper adds an events element to the page definition file. Each event name is added as a child. Example 28-22 shows the event on the setHelpId method action binding in the account_basicinformationPageDef page definition file of the StoreFront module. This is the page definition for the Basic Information view of the customer registration task flow.

Example 28-22 Event Definition for the Producer

<methodAction id="setHelpId"
                  InstanceName="LookupServiceAMDataControl.dataProvider"
                  DataControl="LookupServiceAMDataControl"
                  RequiresUpdateModel="true" Action="invokeMethod"
                  MethodName="setHelpId" IsViewObjectMethod="false"
                  ReturnName="LookupServiceAMDataControl.
                      methodResults.setHelpId_
                      LookupServiceAMDataControl_dataProvider_
                      setHelpId_result">
                  <NamedData NDName="usage" NDValue="CREATE_PROFILE"
                       NDType="java.lang.String"/>
 <events xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
                  <event name="queueHelpTopic"/>
 </events>

When the method action binding is invoked, the event is broadcasted to its consumers.

When you configure an event map, JDeveloper creates an event map entry in the corresponding page definition file. Example 28-23 shows the event map on the registerPageDef page definition file that maps the queueHelpTopic event from the customerregistrationtaskflow1 region to the helptaskflow1 region. It also maps the helpPageDef.findHelpTextById handler method bindings that is defined in the helpPageDef page definition file. The consumer invokes a method that determine the information text to display based on the parameters that are passed into it. The mapping is in the registerPageDef page definition, as that is the parent container for both the customerregistrationtaskflow1 and the helptaskflow1 regions.

Example 28-23 Event Map in the Parent Page Definition File

<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
    <event name="queueHelpTopic">
      <producer region="*">
        <consumer region="helptaskflow1"
                  handler="helpPageDef.findHelpTextById">
         <parameters>
            <parameter name="helpTopicId" value="${payLoad}"/>
          </parameters> 
        </consumer>
      </producer> 
    </event>
</eventMap>

28.7.8 How to Control Contextual Events Dispatch

You can control the dispatch of contextual events to child regions at the application level or at the page level. At the application level, you can disable the event dispatch to regions that has an eventMap with producers as wildCards.

For application level control, set the dynamicEventSubscriptions property to false in the adf-config.xml file, as shown in Example 28-24.

Example 28-24 Disabling Contextual Event Dispatch at the Application Level Using adf-config.xml

<?xml version="1.0" encoding="windows-1252" ?>
<adf-config xmlns="http://xmlns.oracle.com/adf/config"
     xmlns:cef="http://xmlns.oracle.com/adfm/contextualEvent">
     <cef:DynamicRegionEventsConfig dynamicEventSubscriptions="false">
     </cef:DynamicRegionEventsConfig>
</adf-config>

You can also disable contextual event dispatch for individual pages by setting the DynamicEventSubscriptions property to false in the associated page definition file as shown in Example 28-25. Contextual events will not be passed to the page and any of its children.

Example 28-25 Disabling Contextual Event Dispatch for a Page Using the Page Definition File

<pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel"
                version="11.1.1.52.8" id="viewBPageDef" Package="view.pageDefs"
                DynamicEventSubscriptions="false">

28.7.9 What Happens at Runtime: Contextual Events

If both the event producer and the consumer are defined in the same page definition file, then after the corresponding page is invoked and the binding container is created, the event is raised when:

  • The corresponding method or action binding is executed

  • A value binding is set successfully

  • A range binding currency is set successfully

For a method binding, the result of the method execution forms the payload of the event, and the event is queued. In the Invoke Application phase of the JSF lifecycle, all the queued events will be dispatched. The event dispatcher associated with the binding container checks the event map (also in the binding container, as it is part of the same page definition file) for a consumer interested in that event and delivers the event to the consumer. The payload is then removed from the queue.

When the producer and consumer are in different regions, the event is first dispatched to any consumer in the same container, and then the event propagation is delegated to the parent binding container. This process continues until the parent or the topmost binding container is reached. After the topmost binding container is reached, the event is again dispatched to child binding containers which have regions with pages that have producer set to wildcard "* ".

28.8 Adding ADF Model Layer Validation

In the model layer, ADF Model validation rules can be set for a binding's attribute on a particular page. When a user edits or enters data in a field and submits the form, the bound data is validated against any set rules and conditions. If validation fails, the application displays an error message.

Note that you don't need to add additional ADF Model validation if you have already set validation rules in the business domain layer of your entity objects. In an ADF Business Components-based Fusion web application, unless you use data controls other than your application module data controls, you won't need to use ADF Model validation.

You can set the skipValidation property to true to bypass the ADF Model validation. You can set skipValidation to skipDataControls to validate the bound objects without validating the transaction. For instance, set skipValidation to skipDataControls if you have a table action that opens a popup window to accept data entries and you want to allow the view layer to validate those entries before the commit on the table. The skipValidation property can be found in the Property Inspector after you have selected the root node of the page definition file in the Structure window.

28.8.1 How to Add Validation

You set ADF Model validation on the page definition file. You define the validation rule, and set an error message to display when the rule is broken.

Table 28-4 describes the ADF Model validation rules that you can configure for a binding's attributes.

Table 28-4 ADF Model Validation Rules

Validator Rule NameDescription

Compare

Compares the attribute's value with a literal value

List

Validates whether or not the value is in a list of values

Range

Validates whether or not the value is within a range of values

Length

Validates the value's character or byte size against a size and operand (such as greater than or equal to)

Regular Expression

Validates the data using Java regular expression syntax

Required

Validates whether or not a value exists for the attribute


Before you begin:

Create a component on the page. The component must have binding attributes.

To create an ADF Model validation rule:

  1. Open the page definition that contains the binding for which you want to create a rule.

  2. In the Structure window, select the attribute, list, or table binding.

  3. In the Property Inspector, select More and then Edit Validation Rule.

  4. In the Edit Validation Rules dialog, expand the binding node, select the attribute name, and click New.

  5. In the Add Validation Rule dialog, select a validation rule and configure the rule accordingly.

  6. Select the Failure Handling tab and configure the message to display when the rule is broken.

28.8.2 What Happens at Runtime: Model Validation Rules

When a user submits data, as long as the submitted value is a non-null value or a string value of at least one character, then all validators on a component are called one at a time. Because the f:validator tag on the component is bound to the validator property on the binding, any validation routines set on the model are accessed and executed.

The process then continues to the next component. If all validations are successful, the Update Model Values phase starts and a local value is used to update the model. If any validation fails, the current page is redisplayed along with an error message.

28.9 Displaying Error Messages

When you use the Data Controls panel to create input components, JDeveloper inserts the af:messages tag at the top of the page. This tag can display all error messages in the queue for any validation that occurs on the server side, in a box offset by color. If you choose to turn off client-side validation for ADF Faces, those error messages are displayed along with any ADF Model error messages. ADF Model messages are shown first. Messages are shown within the af:messages tag, and with the associated components.

Figure 28-11 shows the error message for an ADF Model validation rule, which states that the value the user entered is not acceptable.

Figure 28-11 Displaying Model Error Messages

Model side error messageg.

You can display server-side error messages in a box at the top of a page using the af:messages tag. When you drop any item from the Data Controls panel onto a page as an input component, JDeveloper automatically adds this tag for you.

To display error messages in an error box:

  1. In the Structure window, select the af:messages tag.

    This tag is created automatically whenever you drop an input widget from the Data Controls panel. However, if you need to insert the tag manually, simply add the code, as shown in Example 28-26, within the af:document tag.

    Example 28-26 Messages Tag in a Page

    <af:document>
      <af:messages globalOnly="false" />
      ...
    </af:document>
    
  2. In the Property Inspector set the following attributes:

    • globalOnly: By default, ADF Faces displays global messages (that is, messages that are not associated with components), followed by individual component messages. If you wish to display only global messages in the box, set this attribute to true. Component messages will continue to display with the associated component.

    • Inline: Specify whether to render the message list inline with the page or in a popup window.

    • message: The main message text that displays just below the message box title, above the list of individual messages.

  3. Ensur*Ne that client-side validation has been disabled. If you do not disable client-side validation, the alert dialog will display whenever there are any ADF Faces validation errors and prevent propagation of the error to the server.

    To disable client-side validation, add an entry for <client-validation-disable> and set it to true in the trinidad-config.xml file, as shown in Example 28-27.

    Example 28-27 Disabling Client-Side Validation in the Trinidad-config.xml

    <?xml version="1.0" encoding="windows-1252"?>
    <trinidad-config xmlns="http://myfaces.apache.org/trinidad/config">
      <skin-family>blafplus-rich</skin-family>
      <client-validation-disabled>true</client-validation-disabled>
    </trinidad-config>
    

28.10 Customizing Error Handling

You can report errors using a custom error handler that extends the default DCErrorHandlerImpl class. You are not required to write any code to register your custom exception handler class. Instead, you select the root node of the DataBindings.cpx file in the Structure window, and then use the Property Inspector to set the ErrorHandlerClass property to the fully qualified name of the error handler you want it to use.

Your custom error handler can contain the following overridable methods:

Example 28-28 illustrates a custom error handler that extends the DCErrorHandlerImpl class and shows the override for the skipException() method that is needed to skip exceptions that should not appear in the list displayed to the user.

Example 28-28 Custom Error Handler

package view.controller.fwkext;

import java.sql.SQLIntegrityConstraintViolationException;

import java.util.ArrayList;
import java.util.List;

import oracle.adf.model.binding.DCBindingContainer; 
import oracle.adf.model.binding.DCErrorHandlerImpl;

import oracle.jbo.CSMessageBundle; 
import oracle.jbo.DMLConstraintException; 
import oracle.jbo.JboException;

public class CustomErrorHandler extends DCErrorHandlerImpl {

   List<ExceptionMapper> exceptionMapperList = new ArrayList<ExceptionMapper>();
   public CustomErrorHandler() {
     this(true);
   }

   public CustomErrorHandler(boolean setToThrow) {
     super(setToThrow); 
     exceptionMapperList.add(new DisableJboExceptionCodesMapper());
   }

   public void reportException(DCBindingContainer bc, Exception ex) { 
     for (ExceptionMapper mapper : exceptionMapperList) {
       if (mapper.canMapException(ex)) { 
         ex = mapper.mapException(ex);
       } 
     }
     super.reportException(bc, ex);
   }

   /**
    * If an exception is a RowValException or a TxnValException and they
    * have nested exceptions, then do not display it. This example shows
    * an implementation that skips the SQLIntegrityConstraintViolationException
    * from displaying in the error final list displayed to the user.
    */
   @Override
   protected boolean skipException(Exception ex) {

      if (ex instanceof DMLConstraintException) {
            return false;
        } else if (ex instanceof SQLIntegrityConstraintViolationException) {
            return true;
        }
        return super.skipException(ex);
    }

}

You must change the constuctor to MyErrorHandler(). The exception error handler must have a default constructor, as shown in Example 28-29.

Example 28-29 Default Constructor

ErrorHandlerClass="viewcontroller.MyErrorHandler" public MyErrorHandler()  {   super(true); }

28.10.1 How to Customize the Detail Portion of a Message

If you plan to customize and use the detail portion of a message, you can create a custom error handler and implement the getDetailedDisplayMessage method to retrieve and process that message. The finalized message will be passed to the view layer to be integrated with other messages.

To customize the detail portion of a message:

  1. Create a custom error handler class that extends the default DCErrorHandlerImpl class.

  2. In that class, override the getDetailedDisplayMessage method that returns a DCErrorMessage object.

    Example 28-30 shows an implementation of the getDetailedDisplayMessage method in the custom error handler class.

    Example 28-30 Custom Error Handler Class with getDetailDisplayMessage Method

    public final class MyErrorMessageHandler extends DCErrorHandlerImpl {
        public MyErrorMessageHandler (){
            super(false);
        }
        public DCErrorMessage getDetailedDisplayMessage(BindingContext ctx,
                                                        RegionBinding ctr,
                                                        Exception ex) {
            ...
            return new MyDCErrorMesssage(ctr, ex);
        }
    }
    
  3. Create a custom class that implements the DCErrorMessage interface. The class must implement the getHTMLText method and the getText method.

    You will add code to the getHTMLText method to perform the actual processing, but you must also implement getText to satisfy the interface requirements.

  4. In the getHTMLText implementation, add code to create and process the error message.

    getHTMLText of getDetailedDisplayMessage should return the finalized version of the error message as an HTML fragment that will be inserted into the HTML code of the page. For this reason, you should perform all necessary preprocessing on the text message before the message is returned by getDetailedDisplayMessage. For instance, you may want to retrieve the localized version of the message or change the right-to-left ordering of the message before it is returned.

    Example 28-31 shows an implementation of this interface.

    Example 28-31 Implementing the DCErrorMessage Interface

    public final class MyDCErrorMesssage implements DCErrorMessage {
        RegionBinding m_regionBinding;
        Exception m_ex;
           public MyDCErrorMesssage(RegionBinding ctr, Exception ex) {
            super();
            this.m_regionBinding = ctr;
            this.m_ex = ex;
        }
        public String getText() {
            ...
            return "Message String";
        }
        public String getHTMLText() {
            ...
            /* Add code to process the message, including localization */
            /* and right-to-left directional requirements. */
            /* Return the message as the finalized HTML fragment.*/
            return "<html><b>error</b> message details</html>";
        }
    }
    

    To format the message using HTML tags, you must enclose the message within <html></html> tags, as shown in the example. Note that only the following HTML tags are allowed in error messages:

    • <span>

    • <b>

    • <a>

    • <i>

    • <em>

    • <br>

    • <hr>

    • <li>

    • <ol>

    • <ul>

    • <p>

    • <tt>

    • <big>

    • <small>

    • <pre>

28.10.2 How to Write an Error Handler to Deal with Multiple Threads

Oracle ADF constructs an instance of the custom error handler for each BindingContext object that is created. Because Oracle ADF serializes simultaneous web requests from the same logical end-user session, multiple threads generally will not use the same error handler at the same time. However, to guarantee a thread-safe custom error handler, use the setProperty() API on JboException. This method stores in the exception objects themselves any hints you might need later during the phase when exceptions are translated to JSF FacesMessage objects for display.

PK`**PKHwEOEBPS/bcquerying.htm Defining SQL Queries Using View Objects

5 Defining SQL Queries Using View Objects

This chapter describes how to create ADF view objects to create SQL queries that join, filter, sort, and aggregate data for use in an Oracle Application Development Framework (Oracle ADF) application. It describes how view objects map their SQL-derived attributes to database table columns and static data source, such as a flat file.

This chapter includes the following sections:

5.1 Introduction to View Objects

A view object is an Oracle Application Development Framework (Oracle ADF) component that encapsulates a SQL query and simplifies working with its results. There are several types of view objects that you can create in your ADF Business Components project:

An entity-based view object can be configured to support updatable rows when you create view objects that map their attributes to the attributes of one or more existing entity objects. The mapped entity object is saved as an entity usage in the view object definition. In this way, entity-based view objects cooperate automatically with entity objects to enable a fully updatable data model. The entity-based view object queries just the data needed for the client-facing task and relies on its mapped entity objects to automatically validate and save changes made to its view rows. Like the read-only view object, an entity-based view object encapsulates a SQL query, it can be linked into master-detail hierarchies, and it can be used in the data model of your application modules.

5.1.1 Overview of View Object Concepts

View objects with no entity usage definition are always read-only. They do not pick up entity-derived default values, they do not reflect pending changes, and they do not reflect updated reference information. In contrast to entity-based view objects, read-only view objects require you to write the query using the SQL query language. The Create View Object wizard and overview editor for entity-based view objects, on the other hand, simplify this task by helping you to construct the SQL query declaratively. For this reason, it is almost always preferable to create a non-updatable, entity-mapped view object, even when you want to create a view object just to read data. Additionally, as an alternative to creating view objects that specify a SQL statement at design time, you can create entity-mapped view objects that dynamically generate SQL statements at runtime.

There remain a few situations where it is still preferable to create a non-entity-mapped view object to read data, including SQL-based validation, Unions, and Group By queries.

This chapter helps you understand these view object concepts as illustrated in Figure 5-1:

  • You define a view object by providing a SQL query (either defined explicitly or declaratively).

  • You use view object instances in the context of an application module that provides the database transaction for their queries.

  • You can link a view object to one or more others to create master-detail hierarchies.

  • At runtime, the view object executes your query and produces a set of rows (represented by a RowSet object).

  • Each row is identified by a corresponding row key.

  • You iterate through the rows in a row set using a row set iterator.

  • You can filter the row set a view object produces by applying a set of Query-by-Example criteria rows.

Figure 5-1 A View Object Defines a Query and Produces a Row Set of Rows

Query produces a row set of rows

5.1.2 Runtime Features Unique to Entity-Based View Objects

When a view object has one or more underlying entity usages, you can create new rows, and modify or remove queried rows. The entity-based view object coordinates with underlying entity objects to enforce business rules and to permanently save the changes to the database. In addition, entity-based view objects provide these capabilities that do not exist with read-only view objects:

  • Changes in cache (updates, inserts, deletes) managed by entities survive the view object's execution boundary.

  • Changes made to relevant entity object attributes through other view objects in the same transaction are immediately reflected.

  • Attribute values of new rows are initialized to the values from the underlying entity object attributes.

  • Changes to foreign key attribute values cause reference information to get updated.

  • Validation for row (entity) level is supported.

  • Composition feature, including validation, locking, ordered-updates is supported.

  • Support for effective dating, change indicator, and business events.

This chapter explains how instances of entity-based view objects contained in the data model of your application module enable clients to search for, update, insert, and delete business domain layer information in a way that combines the full data shaping power of SQL with the clean, object-oriented encapsulation of reusable domain business objects. And all without requiring a line of code.This chapter helps you to understand these entity-based view object concepts as illustrated in Figure 5-2:

  • You define an updatable view object by referencing attributes from one or more entity objects.

  • You can use multiple, associated entity objects to simplify working with reference information.

  • You can define view links based on underlying entity associations.

  • You use your entity-based view objects in the context of an application module that provides the transaction.

  • At runtime, the view row delegates the storage and validation of its attributes to underlying entity objects.

Figure 5-2 View Objects and Entity Objects Collaborate to Enable an Updatable Data Model

Entity-based view objects

5.2 Populating View Object Rows from a Single Database Table

View objects provide the means to retrieve data from a data source. In the majority of cases, the data source will be a database and the mechanism to retrieve data is the SQL query. ADF Business Components can work with JDBC to pass this query to the database and retrieve the result.

When view objects use a SQL query, query columns map to view object attributes in the view object. The definition of these attributes, saved in the view object's XML definition file, reflect the properties of these columns, including data types and precision and scale specifications.


Performance Tip:

If the query associated with the view object contains values that may change from execution to execution, use bind variables. Using bind variables in the query allows the query to reexecute without needing to reparse the query on the database. You can add bind variables to the view object in the Query page of the overview editor for the view object. For more information, see Section 5.10, "Working with Bind Variables."


Using the same Create View Object wizard, you can create view objects that either map to the attributes of existing entity objects or not. Only entity-based view objects automatically coordinate with mapped entity objects to enforce business rules and to permanently save data model changes. Additionally, you can disable the Updatable feature for entity-based view objects and work entirely declaratively to query read-only data. Alternatively, you can use the wizard or editor's expert mode to work directly with the SQL query language, but the view object you create will not support the transaction features of the entity-based view object.

While there is a small amount of runtime overhead associated with the coordination between view object rows and entity object rows, weigh this against the ability to keep the view object definition entirely declarative and maintain a customizable view object. Queries that cannot be expressed in entity objects, and that therefore require expert-mode query editing, include Unions and Group By queries. Expert mode-based view objects are also useful in SQL-based validation queries used by the view object-based Key Exists validator. Again, it is worth repeating that, by definition, using expert mode to define a SQL query means the view object must be read-only.

For more information about the differences between entity-based view objects and read-only view objects, see Section 5.1.2, "Runtime Features Unique to Entity-Based View Objects."

5.2.1 How to Create an Entity-Based View Object

Creating an entity-based view object is the simplest way to create a view object. It is even easier than creating an expert-mode, read-only view object, since you don't have to type in the SQL statement yourself. An entity-based view object also offers significantly more runtime functionality than its expert-mode counterpart.

In an entity-based view object, the view object and entity object play cleanly separated roles:

  • The view object is the data source: it retrieves the data using SQL.

  • The entity object is the data sink: it handles validating and saving data changes.

Because view objects and entity objects have cleanly separated roles, you can build a hundred different view objects — projecting, filtering, joining, sorting the data in whatever way your user interfaces require, application after application — without any changes to the reusable entity object. In fact, it is possible that the development team responsible for the core business domain layer of entity objects might be completely separate from another team responsible for the specific application modules and view objects needed to support the end-user environment. This relationship is enabled by metadata that the entity-based view object encapsulates. The metadata specifies how the SELECT list columns are related to the attributes of one or more underlying entity objects.

Your entity-based view object may be based on more than one database table. To use database joins to add multiple tables to the view object, see Section 5.5, "Working with Multiple Tables in Join Query Results."

5.2.1.1 Creating an Entity-Based View Object from a Single Table

To create an entity-based view object, use the Create View Object wizard, which is available from the New Gallery.

Before you begin:

Create the desired entity objects as described in Section 4.2.1, "How to Create Multiple Entity Objects and Associations from Existing Tables."

To create an entity-based view object from a single table:

  1. In the Application Navigator, right-click the project in which you want to create the view object and choose New.

  2. In the New Gallery, expand Business Tier, select ADF Business Components and then View Object, and click OK.

    If this is the first component you're creating in the project, the Initialize Business Components Project dialog appears to allow you to select a database connection.

  3. In the Initialize Business Components Project dialog, select the database connection or choose New to create a connection. Click OK.

  4. In the Create View Object wizard, on the Name page, enter a package name and a view object name. Keep the default setting Updatable access through entity objects enabled to indicate that you want this view object to manage data with its base entity object. Click Next.

  5. On the Entity Objects page, select an entity object whose data you want to use in the view object. Click Next.

    An entry in this list is known as an entity usage, since it records the entity objects that the view object will be using. Each entry could also be thought of as an entity reference, since the view object references attributes from that entity. For information about working table joins to create additional entity usages, see Section 5.5, "Working with Multiple Tables in Join Query Results."

    For example, Figure 5-3 shows the result after shuttling the PersonEO entity object into the Selected list.

    Figure 5-3 Create View Object Wizard, Entity Objects Page

    Step 2 of the Create View Object wizard
  6. On the Attributes page, select the attributes you want to include from each entity usage in the Available list and shuttle them to the Selected list. Click Next.

    For example, Figure 5-4 shows the attributes have been selected from the PersonEO.

    Figure 5-4 Create View Object Wizard, Attributes Page

    Step 3 of the Create View Object wizard
  7. On the Attribute Settings page, optionally, use the Select Attribute dropdown list to switch between the view object attributes in order to change their names or any of their initial settings.

    For more information about any of the attribute settings, press F1 or click Help.

  8. On the Query page, optionally, add a WHERE and ORDER BY clause to the query to filter and order the data as required. JDeveloper automatically generates the SELECT statement based on the entity attributes you've selected.

    Do not include the WHERE or ORDER BY keywords in the Where and Order By field values. The view object adds those keywords at runtime when it executes the query.

    For example, Figure 5-5 shows the ORDER BY clause is specified to order the data by first name, last name, and email.

    Figure 5-5 Create View Object Wizard, Query Page

    Step 5 of the Create View Object wizard
  9. When you are satisfied with the view object, click Finish.

5.2.1.2 Creating a View Object with All the Attributes of an Entity Object

When you want to allow the client to work with all of the attributes of an underlying entity object, you can use the Create View Object wizard as described in Section 5.2.1.1, "Creating an Entity-Based View Object from a Single Table." After selecting the entity object, simply select all of its attributes on the Attributes page. However, for this frequent operation, there is an even quicker way to perform the same task in the Application Navigator.

Before you begin:

Create the desired entity objects as described in Section 4.2.1, "How to Create Multiple Entity Objects and Associations from Existing Tables."

To create a default entity-based view object:

  1. In the Application Navigator, right-click the entity object and choose New Default View Object.

  2. Provide a package and component name for the new view object in the Create Default View Object dialog.

    In the Create Default View Object dialog you can click Browse to select the package name from the list of existing packages. For example, in Figure 5-6, clicking Browse locates oracle.fodemo.storefront.enties package on the classpath for the StoreFrontService project in the StoreFrontModule application.

Figure 5-6 Shortcut to Creating a Default View Object for an Entity Object

Create Default View Object dialog

The new entity-based view object created will be identical to one you could have created with the Create View Object wizard. By default, it will have a single entity usage referencing the entity object you selected in the Application Navigator, and will include all of its attributes. It will initially have neither a WHERE nor ORDER BY clause, and you may want to use the overview editor for the view object to:

  • Remove unneeded attributes

  • Refine its selection with a WHERE clause

  • Order its results with an ORDER BY clause

  • Customize any of the view object properties

5.2.2 What Happens When You Create an Entity-Based View Object

When you create a view object, JDeveloper creates the XML component definition file that represents the view object's declarative settings and saves it in the directory that corresponds to the name of its package. For example, the view object Orders, added to the queries package, will have the XML file ./queries/Orders.xml created in the project's source path.

To view the view object settings, expand the desired view object in the Application Navigator, select the XML file under the expanded view object, and open the Structure window. The Structure window displays the list of XML definitions, including the SQL query, the name of the entity usage, and the properties of each attribute. To open an XML definition in the editor, right-click the corresponding node and choose Go to Source.


Note:

If you configure JDeveloper preferences to generate default Java classes for ADF Business Components, the wizard will also create an optional custom view object class (for example, OrdersImpl.java) and/or a custom view row class (for example, OrdersRowImpl.java). For details about setting preferences, see Section 39.3.1.4, "Configuring Default Java Generation Preferences."


Figure 5-7 depicts the entity-based view object OrderItemsInfoVO and the three entity usages referenced in its query statement. The dotted lines represent the metadata captured in the entity-based view object's XML component definition that map SELECT list columns in the query to attributes of the entity objects used in the view object. The query of the entity-based view object joins data from a primary entity usage (OrderItemEO) with that from secondary reference entity usages (ProductBaseEO and SupplierEO).

Figure 5-7 View Object Encapsulates a SQL Query and Entity Attribute Mapping Metadata

View objects encapsulate queries and metadata

5.2.3 How to Create an Expert Mode, Read-Only View Object

When you need full control over the SQL statement, the Create View Object wizard lets you specify that you want a view object to be read-only. In this case, you will not benefit from the declarative capabilities to define a non-updatable entity-based view object. However, there are a few situations where it is desirable to create read-only view objects using expert mode. Primarily, the read-only view object that you create will be useful when you need to write Unions or Group By queries. Additionally, you can use a read-only view object if you need to create SQL-based validation queries used by the view object-based Key Exists validator, provided that you have marked a key attribute.


Best Practice:

Unlike entity-based view objects, read-only view objects that you create in expert mode, will not define a key attribute by default. While it is possible to create a read-only view object without defining its key attribute, in expert mode it is a best practice to select the attribute that corresponds to the queried table's primary key and mark it as the key attribute. The presence of a key attribute ensures the correct runtime behavior for row set navigation. For example, the user interface developer may create an LOV component based on the read-only view object collection. Without a key attribute to specify the row key value, the LOV may not behave properly and a runtime error can result.


For more information about the tradeoffs between working with entity-based view objects that you define as non-updatable and strictly read-only view objects, see Section 39.2.2, "Consider Using Entity-Based View Objects for Read-Only Data."

To create a read-only view object, use the Create View Object wizard, which is available from the New Gallery.

To create a read-only view object:

  1. In the Application Navigator, right-click the project in which you want to create the view object and choose New.

  2. In the New Gallery, expand Business Tier, select ADF Business Components and then View Object, and click OK.

    If this is the first component you're creating in the project, the Initialize Business Components Project dialog appears to allow you to select a database connection.

  3. In the Initialize Business Components Project dialog, select the database connection or choose New to create a connection. Click OK.

  4. In the Create View Object wizard, on the Name page, enter a package name and a view object name. Select Read-only access through SQL query to indicate that you want this view object to manage data with read-only access. Click Next.

  5. On the Query page, use one of the following techniques:

    • Paste any valid SQL statement into the Query Statement box. The query statement can use a WHERE clause and an Order By clause. For example, Figure 5-8 shows a query statement that uses a WHERE clause and an Order By clause to query a list of country codes in the language used by the application.

    • Click Query Builder to open the SQL Statement dialog and use the interactive query builder.

      Figure 5-8 Create View Object Wizard, Query Page

      Step 2 of the Create View Object wizard

      Note:

      If the Entity Objects page displays instead of the Query page, go back to Step 1 of the wizard and ensure that you've selected Read-only Access.


  6. After entering or building the query statement, click Next.

  7. On the Bind Variables page, do one of the following:

  8. On the Attribute Settings page, from the Select Attribute dropdown, select the attribute that corresponds to the primary key of the queried table and then enable the Key Attribute checkbox.

    Because the read-only view object is not based on an entity object, the Create View Object wizard does not define a key attribute by default. Failure to define the key attribute can result in unexpected runtime behavior for ADF Faces components with a data control based on the read-only view object collection. In the case of read-only view objects, define the key attribute, as shown in Figure 5-9.

    Figure 5-9 Create View Object Wizard, Attribute Settings Page

    Step 6 of the Create View Object wizard
  9. On the Attribute Mappings page, click Finish.


Note:

In the ADF Business Components wizards and editors, the default convention is to use camel-capped attribute names, beginning with a capital letter and using uppercase letters in the middle of the name to improve readability when the name comprises multiple words.


5.2.4 What Happens When You Create a Read-Only View Object

When you create a view object, JDeveloper first parses the query to infer the following from the columns in the SELECT list:

  • The Java-friendly view attribute names (for example, CountryName instead of COUNTRY_NAME)

    By default, the wizard creates Java-friendly view object attribute names that correspond to the SELECT list column names, as shown in Figure 5-10.

    For information about using view object attribute names to access the data from any row in the view object's result set by name, see Section 6.4, "Testing View Object Instances Programmatically."

  • The SQL and Java data types of each attribute

Figure 5-10 Create View Object Wizard, Attribute Mappings Page

Step 4 of the Create View Object wizard

Each part of an underscore-separated column name like SOME_COLUMN_NAME is turned into a camel-capped word (like SomeColumnName) in the attribute name. While the view object attribute names correspond to the underlying query columns in the SELECT list, the attribute names at the view object level need not match necessarily.


Tip:

You can rename the view object attributes to any names that might be more appropriate without changing the underlying query.


JDeveloper then creates the XML component definition file that represents the view object's declarative settings and saves it in the directory that corresponds to the name of its package. For example, the XML file created for a view object named CountriesVO in the lookups package is ./lookups/CountriesVO.xml under the project's source path.

To view the view object settings, expand the desired view object in the Application Navigator, select the XML file under the expanded view object, and open the Structure window. The Structure window displays the list of XML definitions, including the SQL query and the list of attributes. To open an XML definition in the editor, right-click the corresponding node and choose Go to Source.

5.2.5 How to Edit a View Object

After you've created a view object, you can edit any of its settings in the overview editor for the view object.


Performance Tip:

How you configure the view object to fetch data plays a large role in the runtime performance of the view object. For information about the tuning parameters that you can edit to optimize performance, see Section 6.3.10, "What You May Need to Know About Optimizing View Object Runtime Performance."


To edit a view object definition:

  1. In the Application Navigator, double-click the view object to open the overview editor.

  2. Select a navigation tab to open any editor page where you can adjust the SQL query, change the attribute names, add named bind variables, add UI controls hints, control Java generation options, and edit other settings.

5.2.5.1 Overriding the Inherit Properties from Underlying Entity Object Attributes

One interesting aspect of entity-based view objects is that each attribute that relates to an underlying entity object attribute inherits that attribute's properties. Figure 5-11 shows the Edit Attribute dialog with the inherited attribute selected. You can see that fields like the Java attribute type and the query column type are disabled and their values are inherited from the related attribute of the underlying entity object to which this view object is related. Some properties like the attribute's data type are inherited and cannot be changed at the view object level.

Other properties like Queryable and Updatable are inherited but can be overridden as long as their overridden settings are more restrictive than the inherited settings. For example, the attribute from underlying entity object might have an Updatable setting of Always. As shown Figure 5-11, the Edit Attribute dialog allows you to set the corresponding view object attribute to a more restrictive setting like While New or Never. However, if the attribute in the underlying entity object had instead an Updatable setting of Never, then the editor would not allow the view object's related attribute to have a less restrictive setting like Always.

Figure 5-11 View Object Attribute Properties Inherited from Underlying Entity Object

Edit Attribute dialog displays inherited properties

5.2.5.2 Controlling the Length, Precision, and Scale of View Object Attributes

When you display a particular attribute of the view object in the Edit Attribute dialog, you can see and change the values of the declarative settings that control its runtime behavior. One important property is the Type in the Query Column section, shown in Figure 5-11. This property records the SQL type of the column, including the length information for VARCHAR2 columns and the precision and scale information for NUMBER columns.

Figure 5-12 Custom Attribute Settings in the Edit Attribute Dialog

Edit Attribute dialog displays custom attribute

JDeveloper tries to infer the type of the column automatically, but for some SQL expressions the inferred value might default to VARCHAR2(255). You can update the Type value for this type of attribute to reflect the correct length if you know it. In the case of read-only view objects, this property is editable in the Edit Attribute dialog you display from the overview editor for the view object. In the case of entity-based view objects, you must edit the Type property in the Edit Attribute dialog that you display for the entity object, as described in Section 4.10.2, "How to Indicate Data Type Length, Precision, and Scale."

For example, VARCHAR2(30) which shows as the Type for the FirstName attribute in Figure 5-12 means that it has a maximum length of 30 characters. For a NUMBER column, you would indicate a Type of NUMBER(7,2) for an attribute that you want to have a precision of 7 digits and a scale of 2 digits after the decimal.


Performance Tip:

Your SQL expression can control how long the describe from the database says the column is. Use the SUBSTR() function around the existing expression. For example, if you specify SUBSTR(yourexpression, 1, 15), then the describe from the database will inform JDeveloper that the column has a maximum length of 15 characters.


5.2.5.3 Converting a Read-Only View Object to Allow Attribute Updates

When you use the Create View Object wizard to create a read-only view object, by default the attributes of the view object will not be updateable. Later you may decide to convert the view object to one that permits updates to its SQL-mapped table columns. However, this cannot be accomplished by merely changing the attribute's Updateable property. To convert a read-only view object to one that is updateable, you must add an entity usage that maps to the same table as the one used to create the read-only view object. Choosing an entity usage that defines the same table ensures that you can then remap the SQL-derived view attributes to entity usage attributes corresponding to the same table columns.

To modify a read-only view object to allow updates:

  1. In the Application Navigator, double-click the read-only view object.

  2. In the overview editor, click the Entity Objects navigation tab.

  3. In the Entity Objects page, expand the Available list and double-click the entity object that describes the attributes of the read-only view object.

    The entity object that you double-click will appear in the Selected list as an entity usage. You will need to remap the SQL-derived attributes to corresponding attributes defined by the entity usage.

  4. Click the Query navigation tab, and in the Query page, click the Edit SQL Query button.

  5. In the Edit Query dialog, click Query and then click Attribute Mappings.

  6. In the Attribute Mappings page, perform the following steps to convert all SQL-derived attributes to their corresponding entity usage mapped attribute.

    1. Click an attribute field in the View Attributes column and scroll to the top of the dropdown list to locate the entity usage attributes.

    2. In the entity usage attribute list, select the attribute corresponding to the read-only attribute that you want to remap, as shown in Figure 5-11.

      Figure 5-13 Specifying an Entity-Derived Attribute in the Edit Query Dialog

      Edit Query dialog displays attribute mapping
  7. Click OK.

5.2.5.4 Customizing View Object Attribute Display in the Overview Editor

When you edit view objects in the overview editor, you can customize the Attributes page of the overview editor to make better use of the attributes table displayed for the view object.

Customization choices that you make for the attributes table include the list of attribute properties to display as columns in the attributes table, the order that the columns appear (from left to right) in the attributes table, the sorting order of the columns, and the width of the columns. The full list of columns that you can choose to display correspond to the attribute properties that you might edit in the view object's Edit Attributes dialog.

For example, you can add the Updatable property as a column to display in the attributes table when you want to quickly determine which attributes of your view object are updatable. Or, you can add the attributes' Label property as a column and see the same description as the end user. Or, you might want to view the list of attributes based on their entity usages. In this case, you can display the Entity Usage column and sort the entire attributes table on this column.

When you have set up the attributes table with the list of columns that you find most useful, you can apply the same set of columns to the attributes table displayed for other view objects by right-clicking the attributes table and choose Apply to All View Objects.

To customize the attributes table display:

  1. In the Application Navigator, double-click the view object.

  2. In the overview editor, click the Attributes navigation tab.

  3. In the Attributes page, click the dropdown menu to the right of the attribute column headers (just below the attributes table's button bar) and choose Select Columns.

  4. In the Select Columns dialog, perform any of the following actions.

    1. Click the left/right shuttle buttons to change the list of visible columns in the attributes table of the overview editor. The overview editor displays only those columns corresponding to the attribute properties that appear the Selected list.

    2. Click one of the Move Selection buttons to change the position of the columns in the attributes table of the overview editor. The overview editor displays the attribute properties arranged from left to right starting with the property at the top of the Selected list.

  5. Click OK.

  6. On the Attributes page of the overview editor, perform any of the following actions.

    1. Click any column header to sort all columns in the attributes table by the selected column.

      This feature is particularly useful when you want to focus on a particular column. For example, in the case of an entity-based view object, you can click the Entity Usage column header to group attributes in the attributes table by their underlying entity objects. To save this setting across all view objects that you display in the overview editor, click the dropdown menu to the right of the column headers and choose Apply to All View Objects.

    2. Click any column header border and drag to adjust the width of the attributes table's column.

    3. Click the dropdown icon to the right of the column headers and select among the list of displayed columns to change the visibility of a column in the current attributes table display.

      This feature lets you easily hide columns when you want to simplify the attributes table display in the current view object overview editor.

  7. To extend the changes in the columns (including column list, column order, column sorting, and column width) to all other view object overview editors, click the dropdown menu to the right of the column headers and choose Apply to All View Objects.

    This feature allows you to easily compare the same attributes across view objects. The overview editor will apply the column selections (and order) that you make in the Select Columns dialog and the current attributes table's column sorting and column widths to all view objects that you edit. View objects that are currently displayed in an open overview editor are not updated with these settings; you must close the open view object overview editor and then reopen the view object to see these settings applied.

5.2.5.5 Modifying the Order of Attributes in the View Object Source File

After you create a view object definition, you may decide to change the order of the attributes queried by the view object. This view object editing feature allows you to easily change the order that the attributes will appear in the attributes table displayed on the Attributes page of the view object overview editor. Because this feature acts on specific attributes and alters the XML definition of the current view object, it does not apply to other view objects that you may edit. Alternatively, you can sort the display of attributes on the Attribute page of the view object overview editor without affecting the source file by clicking any column header in the overview editor's attributes table.

To modify the order of attributes in the view object source file:

  1. In the Application Navigator, double-click the view object.

  2. In the overview editor, click the Attributes navigation tab and click Set Source Order.

  3. In the Set Source Order dialog, select the attribute you want to reposition and click one of the Move Selection button.

  4. Click OK.

    This feature has no affect on other view objects that you may edit; it only affects the current view object.

5.2.6 How to Show View Objects in a Business Components Diagram

JDeveloper's UML diagramming lets you create a Business Components diagram to visualize your business domain layer. In addition to supporting entity objects, JDeveloper's UML diagramming allows you to drop view objects onto diagrams as well to visualize their structure and entity usages. For example, if you create a new Business Components Diagram named StoreFrontService Data Model in the oracle.fodemo.storefront package, and drag the CustomerAddressVO view object from the Application Navigator onto the diagram, its entity usages would display, as shown in Figure 5-14. When viewed as an expanded node, the diagram shows a compartment containing the view objects entity usages.

For information about creating the diagram, see Section 4.4, "Creating an Entity Diagram for Your Business Layer."

Figure 5-14 View Object and Its Entity Usages in a Business Components Diagram

Business components diagram for object usages

5.3 Populating View Object Rows with Static Data

ADF Business Components lets you create view objects in your data model project with rows that you populate at design time. Typically, you create view objects with static data when you have a small amount of data to maintain and you do not expect that data to change frequently. The decision whether to use a lookup table from the database or whether to use a static view object based on a list of hardcoded values depends on the size and nature of the data. The static view object is useful when you have no more than 100 entries to list. Any larger number of rows should be read from the database with a conventional table-based view object. The static view object has the advantage of being easily translatable. However, all of the rows of a static view object will be retrieved at once and therefore, using no more than 100 entries yields the best performance.


Best Practice:

When you need to create a view object to access a small list of static data, you should use the static view object rather than query the database. The static view object is ideal for lists not exceeding 100 rows of data. Because the Create View Object wizard saves the data in a resource message file, these data are easily translatable.


Static list view objects are useful as an LOV data source when it is not desirable to query the database to supply the list of values. Suppose your order has the following statuses: open, closed, pending. You can create a static view object with these values and define an LOV on the static view object's status attribute. Because the wizard stores the values of the status view object in a translatable resource file, the UI will display the status values using the resource file corresponding to the application's current locale.

5.3.1 How to Create Static View Objects with Data You Enter

You use the Create View Object wizard to create static view objects. The wizard lets you define the desired attributes (columns) and enter as many rows of data as necessary. The wizard displays the static data table as you create it.


Note:

Because the data in a static view object does not originate in database tables, the view object will be read-only.


You can also use the Create View Object wizard to create the attributes based on data from a comma-separated value (CSV) file format like a spreadsheet file. The wizard will attempt to create the attributes that you define in the wizard with data from the first row of the flat file.

To manually create attributes for a static view object:

  1. In the Application Navigator, right-click the project in which you want to create the static list view object and choose New.

  2. In the New Gallery, expand Business Tier, select ADF Business Components and then View Object, and click OK.

    If this is the first component you're creating in the project, the Initialize Business Components Project dialog appears to allow you to select a database connection.

  3. In the Initialize Business Components Project dialog, select the database connection or choose New to create a connection. Click OK.

  4. In the Create View Object wizard, on the Name page, enter a package name and a view object name. Select Rows populated at design time (Static List) to indicate that you want to supply static list data for this view object. Click Next.

  5. On the Attributes page, click New to add an attribute that corresponds to the columns in the static data table. In the New View Object Attribute dialog, enter a name and select the attribute type. Click OK to return to the wizard, and click Next.

  6. On the Attribute Settings page, do nothing and click Next.

  7. On the Static List page, click the Add icon to enter the data directly into the wizard page. The attributes you defined will appear as the columns for the static data table.

  8. On the Application Module pages, do nothing and click Next.

  9. On the Summary page, click Finish.

5.3.2 How to Create Static View Objects with Data You Import

Using the Import feature of the Create View Object wizard, you can create a static data view object with attributes based on data from a comma-separated value (CSV) file format like a spreadsheet file. The wizard will use the first row of a CSV flat file to identify the attributes and will use the subsequent rows of the CSV file for the data for each attribute. For example, if your application needs to display choices for international currency, you might define the columns Symbol, Country, and Description in the first row and then add rows to define the data for each currency type, as shown in Figure 5-15.

Figure 5-15 Sample Data Ready to Import from CSV Flat File

Sample flat file data

To create attributes of a static view object based on a flat file:

  1. In the Application Navigator, right-click the project in which you want to create the static list view object and choose New.

  2. In the New Gallery, expand Business Tier, select ADF Business Components and then View Object, and click OK.

    If this is the first component you're creating in the project, the Initialize Business Components Project dialog appears to allow you to select a database connection.

  3. In the Initialize Business Components Project dialog, select the database connection or choose New to create a connection. Click OK.

  4. In the Create View Object wizard, on the Name page, enter a package name and a view object name. Select Rows populated at design time (Static List) to indicate that you want to supply static list data for this view object. Click Next.

  5. On the Attributes page, optionally, click New to add an attribute that corresponds to the columns in the static data table. In the New View Object Attribute dialog, enter a name and select the attribute type. Click OK to return to the wizard, and click Next.

    When the static data will be loaded from a CSV flat file, you can optionally skip this step. If you do not create the attributes yourself, the wizard will attempt to use the first row of the CSV file to create the attributes. However, if you create the attributes in the wizard, then the attributes you create must match the order of the columns defined by the flat file. If you have created fewer attributes than columns, the wizard will ignore extra columns during import. Conversely, if you create more attributes than columns, the wizard will define extra attributes with the value NULL.

  6. On the Attribute Settings page, do nothing and click Next.

  7. On the Static List page, click Import to locate the CSV file and display the data in the wizard. Verify the data and edit the values as needed.

    To edit an attribute value, double-click in the value field.

  8. Optionally, click the Add icon or Remove icon to change the number of rows of data. Click Next.

    To enter values for the attributes of a new row, double-click in the value field.

  9. On the Application Module page, do nothing and click Next.

  10. On the Summary page, click Finish.

5.3.3 What Happens When You Create a Static List View Object

When you create a static view object, the overview editor for the view object displays the rows of data that you defined in the wizard. You can use the editor to define additional data, as shown in Figure 5-16.

Figure 5-16 Static Values Page Displays Data

Static values page of overview editor for view object.

The generated XML definition for the static view object contains one transient attribute for each column of data. For example, if you import a CSV file with data that describes international currency, your static view object might contain a transient attribute for Symbol, Country, and Description, as shown in Example 5-1.

Example 5-1 XML Definition for Static View Object

<ViewObject
...
// Transient attribute for first column
  <ViewAttribute
    Name="Symbol"
    IsUpdateable="false"
    IsSelected="false"
    IsPersistent="false"
    PrecisionRule="true"
    Precision="255"
    Type="java.lang.String"
    ColumnType="VARCHAR2"
    AliasName="Symbol"
    SQLType="VARCHAR"/>
// Transient attribute for second column
  <ViewAttribute
    Name="Country"
    IsUpdateable="false"
    IsPersistent="false"
    PrecisionRule="true"
    Precision="255"
    Type="java.lang.String"
    ColumnType="VARCHAR"
    AliasName="Country"
    SQLType="VARCHAR"/>
// Transient attribute for third column
  <ViewAttribute
    Name="Description"
    IsUpdateable="false"
    IsPersistent="false"
    PrecisionRule="true"
    Precision="255"
    Type="java.lang.String"
    ColumnType="VARCHAR"
    AliasName="Description"
    SQLType="VARCHAR"/>
  <StaticList
    Rows="4"
    Columns="3"/>
// Reference to file that contains static data
  <ResourceBundle>
    <PropertiesBundle
      PropertiesFile="model.ModelBundle"/>
  </ResourceBundle>
</ViewObject>

Because the data is static, the overview editor displays no Query page and the generated XML definition for the static view object contains no query statement. Instead, the <ResourceBundle> element in the XML definition references a resource bundle file. The resource bundle file describes the rows of data and also lets you localize the data. When the default resource bundle type is used, the file ModelNameBundle.properties appears in the data model project, as shown in Example 5-2.

Example 5-2 Default Resource Bundle File for Static View Object

model.ViewObj.SL_0_0=USD
model.ViewObj.SL_0_1=United States of America
model.ViewObj.SL_0_2=Dollars
model.ViewObj.SL_1_0=CNY
model.ViewObj.SL_1_1=P.R. China
model.ViewObj.SL_1_2=Yuan Renminbi
model.ViewObj.SL_2_0=EUR
model.ViewObj.SL_2_1=Europe
model.ViewObj.SL_2_2=Euro
model.ViewObj.SL_3_0=JPY
model.ViewObj.SL_3_1=Japan
model.ViewObj.SL_3_2=Yen

5.3.4 Editing Static List View Objects

When you need to make changes to the static list table, double-click the view object in the Application Navigator to open the overview editor for the view object. You can add and delete attributes (columns in the static list table), add or delete rows (data in the static list table), sort individual rows, and modify individual attribute values. The editor will update the view object definition file and save the attribute names in the message bundle file.

5.3.5 What You May Need to Know About Static List View Objects

The static list view object has a limited purpose in the application module's data model. Unlike entity-based view objects, static list view objects will not be updatable. You use the static list view object when you want to display read-only data to the end user and you do not want to create a database table for the small amount of data the static list table contains.

5.4 Limiting View Object Rows Using Effective Date Ranges

Applications that need to query data over a specific date range can generate date-effective row sets. To define an date-effective view object you must create an entity-based view object that is based on an date-effective entity object. User control over the view object's effective date usage is supported by metadata on the view object at design time. At runtime, ADF Business Components generates the query filter that will limit the view rows to an effective date.

5.4.1 How to Create an Date-Effective View Object

Whether or not the query filter for an effective date will be generated depends on the value of the Effective Dated property displayed in the Property Inspector for the view object (to view the property, select any tab in the overview editor for the view object other than Attributes).


Note:

Because the date-effective view object must be based on an date-effective entity object, setting a view object's Effective Dated property to True without an underlying date-effective entity object, will result in a runtime exception.


The overview editor for the view object does not display the date-effective query clause in the WHERE clause. You can use the Explain Plan dialog or Test Query dialog to view the clause. A typical query filter for effective dates looks like this:

(:Bind_SysEffectiveDate BETWEEN Person.EFFECTIVE_START_DATE AND Person.EFFECTIVE_END_DATE)

At runtime, the bind value for the query is obtained from a property of the root application module. In order to set the effective date for a transaction, use code similar to the following snippet:

am.setProperty(ApplicationModule.EFF_DT_PROPERTY_STR, new Date("2008-10-01));

If you do not set EFF_DT_PROPERTY_STR on the application module, the current date is used in the query filter, and the view object returns the effective rows filtered by the current date.

The view object has its own transient attribute, SysEffectiveDate, that you can use to set the effective date for view rows. Otherwise, the SysEffectiveDate attribute value for new rows and defaulted rows is derived from the application module. ADF Business Components propagates the effective date from the view row to the entity object during DML operations only.

Before you begin:

  1. Create an effective dated entity object as described in Section 4.2.8, "How to Store Data Pertaining to a Specific Point in Time."

  2. Use the Create View Object wizard to create the entity-based view object as described in Section 5.2.1, "How to Create an Entity-Based View Object."

    The view object you create should be based on the effective dated entity object you created. In the Attributes page of the wizard, be sure to add the date-effective attributes that specify the start date and end date on the entity object to the Selected list for the view object.

To enable effective dates for a view object using the SysEffectiveDate attribute:

  1. In the Application Navigator, double-click the view object you created based on the effective dated entity object.

  2. In the overview editor, click the General navigation tab.

  3. In the Property Inspector, expand the Name category.

    If the Name category is not displayed in the Property Inspector, click the General navigation tab in the overview editor to set the proper focus.

  4. Verify that the context menu for the Effective Dated property displays True.

  5. In the overview editor, click the Attributes navigation tab and double-click the attribute for the start date.

  6. In the Edit Attribute dialog, verify that Effective Date is enabled and that Start is selected, as shown in Figure 5-17. Verify that the attribute for the end date is also enabled correctly, as shown in the figure. Note that these fields appear grayed out to indicate that they cannot be edited for the view object.

    Figure 5-17 Edit Attribute Dialog Displays Effective Date Settings

    Effective dated view object attribute enabled
  7. Click OK.

    No additional steps are required once you have confirmed that the view object has inherited the desired attributes from the date-effective entity object.

5.4.2 How to Create New View Rows Using Date-Effective View Objects

Creating (inserting) date-effective rows is similar to creating or inserting ordinary view rows. The start date and end date can be specified as follows:

  • The user specifies the effective date on the application module. The start date is set to the effective date, and the end date is set to end of time.

  • The user specifies values for the start date and the end date (advanced).

In either case, during entity validation, the new row is checked to ensure that it does not introduce any gaps or overlaps. During post time, ADF Business Components will acquire a lock on the previous row to ensure that the gap or overlaps are not created upon the row insert.

5.4.3 How to Update Date-Effective View Rows

You can update view rows by using API calls like Row.setAttribute(). ADF Business Components supports various modes to initiate the row update.

To set the update mode, invoke the Row.setEffectiveDateMode(int mode) method with one of the following mode constants.

  • CORRECTION (Correction Mode)

    The effective start date and effective end dates remain unchanged. The values of the other attributes may change. This is the standard row update behavior.

  • UPDATE (Update Mode)

    The effective end date of the row will be set to the effective date. All user modifications to the row values are reverted on this row. A new row with the modified values is created. The effective start date of the new row is set to the effective date plus one day, and the effective end date is set to end of time. The new row will appear after the transaction is posted to the database.

  • UPDATE_OVERRIDE (Update Override Mode)

    The effective end date of the modified row will be set to the effective date. The effective start date of the next row is set to effective date plus one day.

  • UPDATE_CHANGE_INSERT (Change Insert Mode)

    The effective end date of the modified row should be set to the effective date. All user modifications to the row values are reverted on this row. A new row with the modified values will be created. The effective start date of the new row is set to effective date plus one day, and the effective end date is set to effective start date of the next row minus one day. The new row will appear after the transaction is posted to the database.

5.4.4 How to Delete Date-Effective View Rows

ADF Business Components supports various modes to initiate the row deletion. You can mark view rows for deletion by using API calls like RowSet.removeCurrentRow() or Row.remove().

To set the deletion mode, invoke the Row.setEffectiveDateMode(int mode) method with one of the following mode constants.

  • DELETE (Delete Mode)

    The effective date of the row is set to the effective date. The operation for this row is changed from delete to update. All rows with the same noneffective date key values and with an effective start date greater than the effective date are deleted.

  • DELETE_NEXT_CHANGE (Delete Next Change Mode)

    The effective end date of the row is set to the effective end date of the next row with the same noneffective date key values. The operation for this row is changed from delete to update. The next row is deleted.

  • FUTURE_CHANGE (Delete Future Change Mode)

    The effective end date of the row is set to the end of time. The operation for this row is changed from delete to update. All future rows with the same noneffective date key values are deleted.

  • ZAP (Zap Mode)

    All rows with the same non-effective date key values are deleted.

The effective date mode constants are defined on the row interface as well.

5.4.5 What Happens When You Create a Date-Effective View Object

When you create an date-effective view object, the view object inherits the transient attribute SysEffectiveDate from the entity object to store the effective date for the row. Typically, the insert/update/delete operations modify the transient attribute while Oracle ADF decides the appropriate values for effective start date and effective end date.

The query displayed in the overview editor for the date-effective view object does not display the WHERE clause needed to filter the effective date range. To view the full query for the date-effective view object, including the WHERE clause, edit the query and click Explain Plan in the Edit Query dialog. The following sample shows a typical query and query filter for effective dates:

SELECT OrdersVO.ORDER_ID,        OrdersVO.CREATION_DATE, 
       OrdersVO.LAST_UPDATE_DATE
FROM ORDERS OrdersVO
WHERE (:Bind_SysEffectiveDate BETWEEN OrdersVO.CREATION_DATE AND
                                      OrdersVO.LAST_UPDATE_DATE)

Example 5-3 shows sample XML entries that are generated when you create an date-effective view object.

Example 5-3 XML Definition for Date-Effective View Object

<ViewObject
...
// Property that enables date-effective view object.
  IsEffectiveDated="true">
  <EntityUsage
    Name="Orders1"
    Entity="model.OrdersDatedEO"
    JoinType="INNER JOIN"/>
// Attribute identified as the start date
  <ViewAttribute
    Name="CreationDate"
    IsNotNull="true"
    PrecisionRule="true"
    IsEffectiveStartDate="true"
    EntityAttrName="CreationDate"
    EntityUsage="Orders1"
    AliasName="CREATION_DATE"/>
// Attribute identified as the end date
  <ViewAttribute
    Name="LastUpdateDate"
    IsNotNull="true"
    PrecisionRule="true"
    IsEffectiveEndDate="true"
    EntityAttrName="LastUpdateDate"
    EntityUsage="Orders1"
    AliasName="LAST_UPDATE_DATE"/>
// The SysEffectiveDate transient attribute
  <ViewAttribute
    Name="SysEffectiveDate"
    IsPersistent="false"
    PrecisionRule="true"    Type="oracle.jbo.domain.Date"
    ColumnType="VARCHAR2"
    AliasName="SysEffectiveDate"
    Passivate="true"
    SQLType="DATE"/>
</ViewObject>

5.4.6 What You May Need to Know About Date-Effective View Objects and View LInks

Effective dated associations and view links allow queries to be generated that take the effective date into account. The effective date of the driving row is passed in as a bind parameter during the query execution.

While it is possible to create a noneffective dated association between two entities when using the Create Association wizard or Create View Link wizard, JDeveloper will by default make the association or link effective dated if one of the ends is effective dated. However, when the association or view link exists between an effective dated and a noneffective dated object, then at runtime ADF Business Components will inspect the effective dated nature of the view object or entity object before generating the query clause and binding the effective date. The effective date is first obtained from the driving row. If it is not available, then it is obtained from the property EFF_DT_PROPERTY_STR of the root application module. If you do not set EFF_DT_PROPERTY_STR for the application module, the current date is used in the query filter on the driving row and applied to the other side of the association or view link.

5.5 Working with Multiple Tables in Join Query Results

Many queries you will work with will involve multiple tables that are related by foreign keys. In this scenario, you join the tables in a single view object query to show additional descriptive information in each row of the main query result. You use the Create View Object wizard to define the query using declarative options. Whether your view object is read-only or entity-based determines how you can define the join:

Figure 5-18 illustrates the rows resulting from two tables queried by a view object that defines a join query. The join is a single flattened result.

Figure 5-18 Join Query Result

Join query result

5.5.1 How to Create Joins for Entity-Based View Objects

It is extremely common in business applications to supplement information from a primary business domain object with secondary reference information to help the end user understand what foreign key attributes represent. Take the example of the OrderItems entity object. It contains foreign key attribute of type Number like:

  • ProductId, representing the product to which the order item pertains

From experience, you know that showing an end user exclusively these "raw" numerical values won't be very helpful. Ideally, reference information from the view object's related entity objects should be displayed to improve the application's usability. One typical solution involves performing a join query that retrieves the combination of the primary and reference information. This is equivalent to populating "dummy" fields in each queried row with reference information based on extra queries against the lookup tables.

When the end user can change the foreign key values by editing the data, this presents an additional challenge. Luckily, entity-based view objects support easily including reference information that's always up to date. The key requirement to leverage this feature is the presence of associations between the entity object that act as the view object's primary entity usage and the entity objects that contribute reference information.

To include reference entities in a join view object, use the Create View Object wizard. The Create View Object wizard lets you specify the type of join:

  • Inner Join

    Select when you want the view object to return all rows between two or more entity objects, where each entity defines the same primary key column. The inner join view object will not return rows when a primary key value is missing from the joined entities.

  • Outer Join

    Select when you want the view object to return all rows that exist in one entity object, even though corresponding rows do not exist in the joined entity object. Both left and right outer join types are supported. The left and right designation refers to the source (left) and destination (right) entity object named in an association. For details about changing the default inner join to an outer join, see Section 5.5.5, "How to Modify a Default Join Clause to Be an Outer Join When Appropriate."

Both inner joins and outer joins are supported with the following options:

  • Reference

    Select when you want the data from the entity object to be treated as reference information for the view object. Automatic lookup of the data is supported and attribute values will be dynamically fetched from the entity cache when a controlling key attribute changes.

  • Updatable

    Deselect when you want to prevent the view object from modifying any entity attributes in the entity object. By default, the first entity object (primary) in the Selected list is updatable and subsequent entity objects (secondary) are not updatable. To understand how to create a join view object with multiple updatable entity usages, see Section 39.9, "Creating a View Object with Multiple Updatable Entities."

  • Participate in row delete

    Select when you have defined the entity as updatable and you want the action of removing rows in the UI to delete the participating reference entity object. This option is disabled for the primary entity. For example, while it may be possible to delete an order item, it should not be possible to delete the order when a remove row is called from the join view object.

Before you begin:

Create the desired entity objects as described in Section 4.2.1, "How to Create Multiple Entity Objects and Associations from Existing Tables."

To create a view object that joins entity objects:

  1. In the Application Navigator, right-click the project in which you want to create the view object and choose New.

    When you want to modify an existing view object that you created to include reference information from its related entity objects, double-click the view object and open the Entity Objects page in the overview editor for the view object.

  2. In the New Gallery, expand Business Tier, select ADF Business Components and then View Object, and click OK.

  3. In the Create View Object wizard, on the Name page, enter a package name and a view object name. Keep the default setting Updatable Access Through Entity Objects enabled to indicate that you want this view object to manage data with its base entity object. Click Next.

  4. In the Entity Objects page, the first entity usage in the Selected list is known as the primary entity usage for the view object. Select the primary entity object from the Available list and shuttle it to the Selected list.

    The list is not limited to a single, primary entity usage.

  5. To add additional, secondary entity objects to the view object, select them in the Available list and shuttle them to the Selected list.

    The Association dropdown list shows you the name of the association that relates the selected secondary entity usage to the primary one. For example, Figure 5-19 shows the result of adding one secondary reference entity usage, ShippingOptionTranslationEO, in addition to the primary ShippingOptionBaseEO entity usage. The association that relates to this secondary entity usage is ShippingOptionTranslationFkAssociation.

    Figure 5-19 Create View Object Wizard, Entity Objects Page

    Entity Object page in View Object wizard
  6. Optionally, use the Alias field to give a more meaningful name to the entity usage when the default name is not clear.

  7. If you add multiple entity usages for the same entity, use the Association dropdown list to select which association represents that usage's relationship to the primary entity usage. Click Next.

    For each secondary entity usage, the Reference option is enabled to indicate that the entity provides reference information and that it is not the primary entity. The Updatable option is disabled. This combination represents the typical usage. However, when you want to create a join view object with multiple, updatable entity usages, see Section 39.9, "Creating a View Object with Multiple Updatable Entities."

    Secondary entity usages that are updatable can also have the Participate in row delete option enabled. This will allow secondary entity attributes to appear NULL when the primary entity is displayed.

  8. On the Attributes page, select the attributes you want each entity object usage to contribute to the view object. Click Next.

  9. On the Attribute Settings page, you can rename an attribute when the names are not as clear as they ought to be.

    The same attribute name often results when the reference and secondary entity objects derive from the same table. Figure 5-20 shows the attribute ShippingOptionId1 in the Select Attribute dropdown list, which has been renamed to ShippingOptionTranslationId in the Name field.

    Figure 5-20 Create View Object Wizard, Attribute Settings Page

    Attribute Setting page in View Object wizard
  10. Click Finish.

5.5.2 How to Select Additional Attributes from Reference Entity Usages

After adding secondary entity usages, you can use the overview editor for the view object to select the specific, additional attributes from these new usages that you want to include in the view object.


Tip:

The overview editor lets you sort attributes displayed in the Attributes page by their entity usages. By default, the attributes table displays attributes in the order they appear in the underlying entity object. To sort the attributes by entity usage, click the header for the Entity Usage column of the attributes table. If the Entity Usage column does not appear in the attributes table, click the dropdown menu icon on the top-right corner of the table (below the button bar) and choose Select Columns to add the column to the Selected list.


To select attributes from a secondary entity usage:

  1. In the Application Navigator, double-click the view object.

  2. In the overview editor, click the Attributes navigation tab and click the Add from Entity button to view the list of available entity-derived attributes.

  3. In the Attributes dialog, select the desired attribute and add it to the Selected list.

    Note that even if you didn't intend to include them, JDeveloper automatically verifies that the primary key attribute from each entity usage is part of the Selected list. If it's not already present in the list, JDeveloper adds it for you. When you are finished, the overview editor Query page shows that JDeveloper has included the new columns in the SELECT statement.

  4. Click OK.

5.5.3 How to Remove Unnecessary Key Attributes from Reference Entity Usages

The view object attribute corresponding to the primary key attribute of the primary entity usage acts as the primary key for identifying the view row. When you add secondary entity usages, JDeveloper marks the view object attributes corresponding to their primary key attributes as part of the view row key as well. When your view object consists of a single updatable primary entity usage and a number of reference entity usages, the primary key attribute from the primary entity usage is enough to uniquely identify the view row. Further key attributes contributed by secondary entity usages are not necessary and you should disable their Key Attribute settings.

For example, based on the view object with primary entity usage ShippingOptionEO, you could disable the Key Attribute property for the ShippingOptionTranslationEO entity usage so that this property is no longer selected for this additional key attribute: ShippingTranslationsId.

To remove unnecessary key attributes:

  1. In the Application Navigator, double-click the view object.

  2. In the overview editor, click the Attributes navigation tab.

  3. In the Attributes page, in the attributes table, select the key attribute (identified by the key icon in the Name column), and click the Edit selected attribute(s) button.

  4. In the View Attribute page of the Edit Attribute dialog, deselect the Key Attribute property.

  5. Click OK.

5.5.4 How to Hide the Primary Key Attributes from Reference Entity Usages

Since you generally won't want to display the primary key attributes that were automatically added to the view object, you can set the attribute's Display Hint property in the Control Hints page of the Edit Attribute dialog to Hide.

To hide the primary key attribute:

  1. In the Application Navigator, double-click the view object.

  2. In the overview editor, click the Attributes navigation tab.

  3. In the Attributes page, in the attributes table, select the primary key attribute (identified by the key icon in the Name column), and click the Edit selected attribute(s) button.

  4. In the Control Hints page of the Edit Attribute dialog, select Hide in the Display Hint dropdown list.

  5. Click OK.

5.5.5 How to Modify a Default Join Clause to Be an Outer Join When Appropriate

When you add a secondary entity usage to a view object, the entity usage is related to an entity usage that precedes it in the list of selected entities. This relationship is established by an entity association displayed in the Association dropdown list in the Entity Objects page of the overview editor for the view object. You use the Association dropdown list in the editor to select the entity association that relates the secondary entity usage to the desired preceding entity usage in the Selected list. The name of the preceding entity usage is identified in the Source Usage dropdown list.

When JDeveloper creates the WHERE clause for the join between the table for the primary entity usage and the tables for related secondary entity usages, by default it always creates inner joins. You can modify the default inner join clause to be a left or right outer join when appropriate. The left designation refers to the source entity object named in the selected association. This is the entity identified in the Source Usage dropdown list. The right designation refers to the current secondary entity usage that you have selected in the Selected list.

In the left outer join, you will include all rows from the left table (related to the entity object named in the Source Usage list) in the join, even if there is no matching row from the right table (related to the current secondary entity object selection). The right outer join specifies the reverse scenario: you will include all rows from the right table (related to the entity object named in the Source Usage list) in the join, even if there is no matching row from the left table (related to the current secondary entity object selection).

For example, assume that a person is not yet assigned a membership status. In this case, the MembershipId attribute will be NULL. The default inner join condition will not retrieve these persons from the MEMBERSHIPS_BASE table. Assuming that you want persons without membership status to be viewable and updatable through the MembershipDiscountsVO view object, you can use the Entity Objects page in the overview editor for the view object to change the query into an left outer join to the MEMBERSHIPS_BASE table for the possibly null MEMBERSHIP_ID column value. When you add the person entity to the view object, you would select the left outer join as the join type. As shown in Figure 5-21, the association PersonsMembershipsBaseFkAssoc identifies a source usage MembershipBaseEO on the left side of the join and the selected PersonEO entity usage on the right side. The view object MembershipDiscountsVO joins the rows related to both of these entity objects and defines a left outer join for PersonEO to allow the view object to return rows from the table related to MembershipBaseEO even if they do not have a match in the table related to PersonEO.

Figure 5-21 Setting an Outer Join to Return NULL Rows from Joined Entities

Outer join set on entity-based view object

The view object's updated WHERE clause includes the addition (+) operator on the right side of the equals sign for the related table whose data is allowed to be missing in the left outer join:

PersonEO.MEMBERSHIP_ID = MembershipBaseEO.MEMBERSHIP_ID(+)

Before you begin:

Create the desired entity objects and associations as described in Section 4.2.1, "How to Create Multiple Entity Objects and Associations from Existing Tables."

To change an inner join type to an outer join:

  1. In the Application Navigator, double-click the view object.

  2. In the overview editor, click the Entity Objects navigation tab.

    The entity object you select represents the table on the right side of the join.

  3. In the Entity Objects page, in the Selected list, select the entity object that you want to change the join type for.

    The entity object you select represents the table on the right side of the join.

  4. In the Association dropdown list, if only one association is defined, leave it selected; otherwise, select among the list of entity object associations that relate the secondary entity object to the desired entity object. The entity usage that represents the joined table will be displayed in the Source Usage dropdown list.

    The entity object in the Source Usage dropdown list that you choose through the association selection represents the table on the left side of the join.

  5. In the Join Type dropdown list, decide how you want the view object to return rows from the joined entity objects:

    • left outer join will include rows from the left table in the join, even if there is no matching row from the right table.

    • right outer join will include rows from the right table in the join, even if there is no matching row from the left table.

    The Source Usage dropdown list is the left side of the join and the current entity usage in the Selected list is the right side.

5.5.6 What Happens When You Reference Entities in a View Object

When you create a join view object to include secondary entity usages by reference, JDeveloper updates the view object's XML component definition to include information about the additional entity usages. For example, the ShippingOptionsVO.xml file for the view object includes an additional reference entity usage. You will see this information recorded in the multiple <EntityUsage> elements. For example, Example 5-0 shows an entity usage entry that defines the primary entity usage.

Example 5-4 Primary Entity Usage

<EntityUsage
   Name="ShippingOptionBaseEO"
   Entity="oracle.fodemo.storefront.entities.ShippingOptionBaseEO"/>

The secondary reference entity usages will have a slightly different entry, including information about the association that relates it to the primary entity usage, like the entity usage shown in Example 5-5.

Example 5-5 Secondary Reference Entity Usage

<EntityUsage
   Name="ShippingOptionTranslationEO"
   Entity="oracle.fodemo.storefront.entities.ShippingOptionTranslationEO"
   Association="oracle.fodemo.storefront.entities.associations.
                    ShippingOptionTranslationFkAssoc"
   AssociationEnd="oracle.fodemo.storefront.entities.associations.
                    ShippingOptionTranslationFkAssoc.ShippingOptionTranslation"
   SourceUsage="oracle.fodemo.storefront.store.queries.ShippingOptionsVO.
                    ShippingOptionBaseEO"
   ReadOnly="true"
   Reference="true"/>

Each attribute entry in the XML file indicates which entity usage it references. For example, the entry for the ShippingOptionId attribute in Example 5-6 shows that it's related to the ShippingOptionBaseEO entity usage, while the ShippingMethod attribute is related to the ShippingOptionTranslationEO entity usage.

Example 5-6 Entity Usage Reference of View Object Attribute

   <ViewAttribute
      Name="ShippingOptionId"
      IsNotNull="true"
      EntityAttrName="ShippingOptionId"
      EntityUsage="ShippingOptionBaseEO"
      AliasName="SHIPPING_OPTION_ID" >
   </ViewAttribute>
...
   <ViewAttribute
      Name="ShippingMethod"
      IsUpdatable="true"
      IsNotNull="true"
      EntityAttrName="ShippingMethod"
      EntityUsage="ShippingOptionTranslationEO"
      AliasName="SHIPPING_METHOD" >
   </ViewAttribute>

The Create View Object wizard uses this association information at design time to automatically build the view object's join WHERE clause. It uses the information at runtime to enable keeping the reference information up to date when the end user changes foreign key attribute values.

5.5.7 How to Create Joins for Read-Only View Objects

To create a read-only view object joining two tables, use the Create View Object wizard.

To create a read-only view object joining two tables:

  1. In the Application Navigator, right-click the project in which you want to create the view object and choose New.

  2. In the New Gallery, expand Business Tier, select ADF Business Components and then View Object, and click OK.

  3. In the Initialize Business Components Project dialog, select the database connection or choose New to create a connection. Click OK.

  4. In the Create View Object wizard, on the Name page, enter a package name and a view object name. Select Read-only access through SQL query to indicate that you want this view object to manage data with read-only access. Click Next.

  5. On the Query page, use one of the following techniques to create the SQL query statement that joins the desired tables:

  6. After entering or building the query statement, click Next.

  7. On the Bind Variables page, do one of the following:

  8. On the Attribute Mappings page, click Finish.

5.5.8 How to Test the Join View

To test the new view object, edit the application module and on the Data Model page add an instance of the new view object to the data model. Then, use the Business Component Browser to verify that the join query is working as expected. For details about editing the data model and running the Business Component Browser, see Section 6.3, "Testing View Object Instances Using the Business Component Browser."

5.5.9 How to Use the Query Builder with Read-Only View Objects

The Quick-pick objects page of the SQL Statement dialog lets you view the tables in your schema, including the foreign keys that relate them to other tables. To include columns in the select list of the query, shuttle the desired columns from the Available list to the Selected list. For example, Figure 5-22 shows the result of selecting the PRODUCT_ID, PRODUCT_NAME, and COST_PRICE columns from the PRODUCTS table, along with the SUPPLIER_NAME column from the SUPPLIERS table. The column from the second table appears, beneath the PRODUCTS_SUPPLIERS_FK foreign key in the Available list. When you select columns from tables joined by a foreign key, the query builder automatically determines the required join clause for you.

Figure 5-22 View Object Query Builder to Define a Join

SQL Statement dialog

Optionally, use the WHERE clause page of the SQL Statement dialog to define the expression. To finish creating the query, click OK in the SQL Statement dialog. The Edit Query dialog will show a query like the one shown in Example 5-7.

Example 5-7 Creating a Query Using SQL Builder

SELECT
    PRODUCTS_BASE.PRODUCT_ID PRODUCT_ID,
    PRODUCTS_BASE.PRODUCT_NAME PRODUCT_NAME,
    PRODUCTS_BASE.COST_PRICE COST_PRICE,
    SUPPLIERS.SUPPLIER_NAME SUPPLIER_NAME
FROM
    PRODUCTS_BASE JOIN SUPPLIERS USING (SUPPLIER_ID)

You can use the Attributes page of the Create View Object wizard to rename the view object attribute directly as part of the creation process. Renaming the view object here saves you from having to edit the view object again, when you already know the attribute names that you'd like to use. As an alternative, you can also alter the default Java-friendly name of the view object attributes by assigning a column alias, as described in Section 5.9.2, "How to Name Attributes in Expert Mode."

5.5.10 What You May Need to Know About Join View Objects

If your view objects reference multiple entity objects, they are displayed as separate entity usages on a business components diagram.

5.6 Working with Multiple Tables in a Master-Detail Hierarchy

Many queries you will work with will involve multiple tables that are related by foreign keys. In this scenario, you can create separate view objects that query the related information and then link a "source" view object to one or more "target" view objects to form a master-detail hierarchy.

There are two ways you might handle this situation. You can either:

In either case, you use the Create View Link wizard to define the relationship.

Figure 5-23 illustrates the multilevel result that master-detail linked queries produce.

Figure 5-23 Linked Master-Detail Queries

Linked master-detail queries

5.6.1 How to Create a Master-Detail Hierarchy for Read-Only View Objects

When you want to show the user a set of master rows, and for each master row a set of coordinated detail rows, then you can create view links to define how you want the master and detail view objects to relate. For example, you could link the Persons view object to the Orders view object to create a master-detail hierarchy of customers and the related set of orders they have placed.

To create the view link, use the Create View Link wizard.

Before you begin:

Create the desired read-only view objects as described in Section 5.2.3, "How to Create an Expert Mode, Read-Only View Object."

To create a view link between read-only view objects:

  1. In the Application Navigator, right-click the project in which you want to create the view object and choose New.

  2. In the New Gallery, expand Business Tier, select ADF Business Components and then View Link, and click OK.

  3. In the Create View Link wizard, on the Name page, enter a package name and a view link name. For example, given the purpose of the view link, a name like OrdersPlacedBy is a valid name. Click Next.

  4. On the View Objects page, select a "source" attribute from the view object that will act as the master.

    For example, Figure 5-24 shows the PersonId attribute selected from the PersonsVO view object to perform this role. Click Next.

  5. On the View Objects page, select a corresponding destination attribute from the view object that will act as the detail.

    For example, if you want the detail query to show orders that were placed by the currently selected customer, select the CustomerId attribute in the OrdersVO to perform this role.

  6. Click Add to add the matching attribute pair to the table of source and destination attribute pairs below. When you are finished defining master and detail link, click Next.

    Figure 5-24 shows just one (PersonId,CustomerId) pair. However, if you require multiple attribute pairs to define the link between master and detail, repeat the steps for the View Objects page to add additional source-target attribute pairs.

    Figure 5-24 Defining Source/Target Attribute Pairs While Creating a View Link

    Step 2 of the Create View Link wizard
  7. On the View Link Properties page, you can use the Accessor Name field to change the default name of the accessor that lets you programmatically access the destination view object.

    By default, the accessor name will match the name of the destination view object. For example, you might change the default accessor name OrdersVO to CustomerOrders to better describe the master-detail relationship that the accessor defines.

  8. Also on the View Link Properties page, you control whether the view link represents a one-way relationship or a bidirectional one.

    By default, a view link is a one-way relationship that allows the current row of the source (master) to access a set of related rows in the destination (detail) view object. For example, in Figure 5-25, the checkbox settings indicate that you'll be able to access a detail collection of rows from OrdersVO for the current row in PersonsVO, but not vice versa. In this case, this behavior is specified by the checkbox setting in the Destination Accessor group box for the OrdersVO (the Generate Accessor In View Object: PersonsVO box is selected) and checkbox setting in the Source Accessor group box for PersonsVO (the Generate Accessor In View Object: OrdersVO box is not selected).

    Figure 5-25 View Link Properties Control Name and Direction of Accessors

    Step 3 of the Create View Link wizard
  9. On the Edit Source Query page, preview the view link SQL predicate that will be used at runtime to access the master row in the source view object and click Next.

  10. On the Edit Destination Query page, preview the view link SQL predicate that will be used at runtime to access the correlated detail rows from the destination view object for the current row in the source view object and click Next.

  11. On the Application Module page, add the view link to the data model for the desired application module and click Finish.

    By default the view link will not be added to the application module's data model. Later you can add the view link to the data model using the overview editor for the application module.

5.6.2 How to Create a Master-Detail Hierarchy for Entity-Based View Objects

Just as with read-only view objects, you can link entity-based view objects to other view objects to form master-detail hierarchies of any complexity. The only difference in the creation steps involves the case when both the master and detail view objects are entity-based view objects and their respective entity usages are related by an association. In this situation, since the association captures the set of source and destination attribute pairs that relate them, you create the view link just by indicating which association it should be based on.

To create an association-based view link, you use the Create View Link wizard.

Before you begin:

Create the desired entity-based view objects as described in Section 5.2.1, "How to Create an Entity-Based View Object."

To create an association-based view link

  1. In the Application Navigator, right-click the project in which you want to create the view object and choose New.

    To avoid having to type in the package name in the Create View Link wizard, you can choose New View Link on the context menu of the links package node in the Application Navigator.

  2. In the New Gallery, expand Business Tier, select ADF Business Components and then View Link, and click OK.

  3. In the Create View Link wizard, on the Name page, supply a package and a component name.

  4. On the View Objects page, in the Select Source Attribute tree expand the source view object in the desired package. In the Select Destination Attribute tree expand the destination view object.

    For entity-based view objects, notice that in addition to the view object attributes, relevant associations also appear in the list.

  5. Select the same association in both Source and Destination trees. Then click Add to add the association to the table below.

    For example, Figure 5-26 shows the same OrderItemsOrdersFkAssoc association in both Source and Destination trees selected.

    Figure 5-26 Master and Detail Related by an Association Selection

    Step 2 of the Create View Link wizard
  6. Click Finish.

5.6.3 What Happens When You Create Master-Detail Hierarchies Using View Links

When you create a view link or an association-based view link, JDeveloper creates the XML component definition file that represents its declarative settings and saves it in the directory that corresponds to the name of its package. For example, if the view link is named OrderInfoToOrderItemsInfo and it appears in the queries.links package, then the XML file created will be ./queries/link/OrderInfoToOrderItemsInfo.xml under the project's source path. This XML file contains the declarative information about the source and target attribute pairs you've specified and, in the case of an association-based view link, contains the declarative information about the association that relates the source and target view objects you've specified.

In addition to saving the view link component definition itself, JDeveloper also updates the XML definition of the source view object in the view link relationship to add information about the view link accessor you've defined. As a confirmation of this, you can select the source view object in the Application Navigator and inspect its details in the Structure window. As shown in Figure 5-27, you can see the defined accessor in the ViewLink Accessors node for the OrderItemsInfoVO source view object of the OrderInfoToOrderItemsInfo view link.

Figure 5-27 View Object with View Link Accessor in the Structure Window

Structure window showing view link accessor

Note:

A view link defines a basic master-detail relationship between two view objects. However, by creating more view links you can achieve master-detail hierarchies of any complexity, including:

  • Multilevel master-detail-detail

  • Master with multiple (peer) details

  • Detail with multiple masters

The steps to define these more complex hierarchies are the same as the ones covered in Section 5.6.2, "How to Create a Master-Detail Hierarchy for Entity-Based View Objects," you just need to create it one view link at time.


5.6.4 How to Enable Active Master-Detail Coordination in the Data Model

When you enable programmatic navigation to a row set of correlated details by defining a view link as described in Section 5.6.2, "How to Create a Master-Detail Hierarchy for Entity-Based View Objects," the view link plays a passive role, simply defining the information necessary to retrieve the coordinated detail row set when your code requests it. The view link accessor attribute is present and programmatically accessible in any result rows from any instance of the view link's source view object. In other words, programmatic access does not require modifying the application module's data model.

However, since master-detail user interfaces are such a frequent occurrence in enterprise applications, the view link can be also used in a more active fashion so you can avoid needing to coordinate master-detail screen programmatically. You opt to have this active master-detail coordination performed by explicitly adding an instance of a view-linked view object to your application module's data model.

To enable active master-detail coordination, open the application module in the overview editor and select the Data Model page.

Before you begin:

Create the desired view objects as described in Section 5.2.1, "How to Create an Entity-Based View Object" and Section 5.2.3, "How to Create an Expert Mode, Read-Only View Object."

To add a detail instance of a view object:

  1. In the Application Navigator, double-click the application module.

  2. In the overview editor, click the Data Model navigation tab.

  3. In the Data Model page, expand the View Object Instances section and, in the Available View Objects list, select the detail view object node that is indented beneath the master view object.

    Note that the list shows the detail view object twice: once on its own, and once as a detail view object via the view link. For example, in Figure 5-28 you would select the detail view object OrderItemsInfoVO via OrderInfoToOrderItemInfo instead of the view object labeled as OrderItemsInfoVO (which, in this case, appears beneath the highlighted view object).

    Figure 5-28 Detail View Object Selection from Available View Objects

    Detail view object selection in data model
  4. Enter a name for the detail instance you're about to create in the Name View Instance field below the Available View Objects list.

    For example, Figure 5-28 shows the name OrderItemsDetailVO for the instance of the OrderItemsInfoVO view object that is a detail view.

  5. In the Data Model list, select the instance of the view object that you want to be the actively-coordinating master.

  6. Click Add Instance to add the detail instance to the currently selected master instance in the data model, with the name you've chosen.

    For example, in Figure 5-29, the Data Model list shows a master-detail hierarchy of view object instances with OrderItemsDetailVO as the detail view object.

Figure 5-29 Data Model with View Linked View Object

Data model with view linked view object

5.6.5 How to Test Master-Detail Coordination

To test active master-detail coordination, launch the Business Component Browser on the application module by choosing Run from its context menu in the Application Navigator. The Business Component Browser data model tree shows the view link instance that is actively coordinating the detail view object instance with the master view object instance. You can double-click the view link instance node in the tree to open a master-detail data view page in the Business Component Browser. Then, when you use the toolbar buttons to navigate in the master view object — changing the view object's current row as a result — the coordinated set of details is automatically refreshed and the user interface stays in sync.

If you double-click another view object that is not defined as a master and detail, a second tab will open to show its data; in that case, since it is not actively coordinated by a view link, its query is not constrained by the current row in the master view object.

For information about editing the data model and running the Business Component Browser, see Section 6.3, "Testing View Object Instances Using the Business Component Browser."

5.6.6 How to Access the Detail Collection Using the View Link Accessor

To work with view links effectively, you should also understand that view link accessor attributes return a RowSet object and that you can access a detail collection using the view link accessor programmatically.

5.6.6.1 Accessing Attributes of Row by Name

At runtime, the getAttribute() method on a Row object allows you to access the value of any attribute of that row in the view object's result set by name. The view link accessor behaves like an additional attribute in the current row of the source view object, so you can use the same getAttribute() method to retrieve its value. The only practical difference between a regular view attribute and a view link accessor attribute is its data type. Whereas a regular view attribute typically has a scalar data type with a value like 303 or ngreenbe, the value of a view link accessor attribute is a row set of zero or more correlated detail rows. Assuming that curUser is a Row object from some instance of the Orders view object, you can write a line of code to retrieve the detail row set of order items:

RowSet items = (RowSet)curUser.getAttribute("OrderItems");

Note:

If you generate the custom Java class for your view row, the type of the view link accessor will be RowIterator. Since at runtime the return value will always be a RowSet object, it is safe to cast the view link attribute value to RowSet.


5.6.6.2 Programmatically Accessing a Detail Collection Using the View Link Accessor

Once you've retrieved the RowSet object of detail rows using a view link accessor, you can loop over the rows it contains just as you would loop over a view object's row set of results, as shown in Example 5-8.

Example 5-8 Programmatically Accessing a Detail Collection

while (items.hasNext()) {
  Row curItem = items.next();
  System.out.println("--> (" + curItem.getAttribute("LineItemId") + ") " + 
                     curItem.getAttribute("LineItemTotal"));
}

For information about creating a test client, see Section 6.4.6, "How to Access a Detail Collection Using the View Link Accessor."

5.7 Working with a Single Table in a Recursive Master-Detail Hierarchy

A recursive data model is one that utilizes a query that names source and destination attributes in a master-detail relationship based on a single table. In a typical master-detail relationship, the source attribute is supplied by the primary key attribute of the master view object and the destination attribute is supplied by foreign key attribute in the detail view object. For example, a typical master-detail relationship might relate the DepartmentId attribute on the DEPARTMENT table and the corresponding DepartmentId attribute on the EMPLOYEE table. However, in a recursive data model, the source attribute EmployeeId and the target attribute ManagerId both exist in the EMPLOYEE table. The query for this relationship therefore involves only a single view object. In this scenario, you create the view object for a single base entity object that specifies both attributes and then you define a self-referential view link to configure this view object as both the "source" and the "target" view object to form a master-detail hierarchy.

After you create the view link, there are two ways you can handle the recursive master-detail hierarchy in the data model project. You can either:

5.7.1 How to Create a Recursive Master-Detail Hierarchy for an Entity-Based View Object

In a recursive master-detail hierarchy, the attributes of the view object that you select for the source and destination in the view link will typically be the same pair of attributes that define the self-referential association between the underlying entity object, if this association exists. While this underlying association is not required to create the view link, it does simplify the creation of the view link, so you will first create a foreign key association for the base entity object of the view object.

To create an association, you use the Create Association wizard. Then the association will appear as a selection choice when you use the Create View Link wizard. The view link will be self-referential because the association you select for the source and the destination view object names the same entity object, which is derived from a single database table.

Before you begin:

  • When you create the view link JDeveloper won't be able to infer the association between the source and destination attributes of the entity object. To support the recursive hierarchy, you can use the Create Association wizard to create an association between the source attribute and the destination attribute. On the Entity Objects page, select the same entity object to specify the source and destination attributes and leave all other default selections unchanged in the wizard. For details about creating an association, see Section 4.3, "Creating and Configuring Associations."

    For example, assume the recursive master-detail hierarchy displays a list of employees based on their management hierarchy. In this scenario, you would create the association based on the Employees entity object. On the Entity Objects page of the Create Association wizard, you would select Employees.EmployeeId as the source attribute and Employee.ManagerId as the destination attribute. The entity object Employees supplies both attributes to ensure the association is self-referential.

  • Create the entity-based view object and create a view criteria that will filter the view instance's results to include only those rows you want to see at the "root" of the hierarchy. To create a view criteria that uses a bind variable to filter the view object, see Section 5.11, "Working with Named View Criteria."

    For example, in a recursive hierarchy of managers and employees, you would create the entity-based view object EmployeesView. After you create the view object in the Create View Object wizard, you can use the Query page of the overview editor to create a bind variable and view criteria which allow you to identify the employee or employees that will be seen at the top of the hierarchy. If only a single employee should appear at the root of the hierarchy, then the view criteria in this scenario will filter the employees using a bind variable for the employee ID (corresponding to the source attribute) and the WHERE clause shown in the Create View Criteria dialog would look like ( (Employees.EMPLOYEE_ID = :TheEmployeeId ) ) , where TheEmployeeId is the bind variable name. For more information on creating a view criteria that uses a bind variable to filter the view object, see Section 5.12.2.1, "Creating a Data Source View Object to Control the Cascading List."

    When you are ready to expose the employees view object in your project's data model, you will configure the view instance in the data model to use this view criteria to filter the initial employee in the root of the tree. You'll configure the bind variable to specify the employee ID of the employee that you want to be the root value of the entire hierarchy. For example, the root value of the recursive hierarchy of managers and employees would be the employee ID of the highest level manager in the organization.

To create an association-based, self-referential view link:

  1. In the Application Navigator, right-click the project in which you want to create the view object and choose New.

    To avoid having to type in the package name in the Create View Link wizard, you can choose New View Link on the context menu of the links package node in the Application Navigator.

  2. In the New Gallery, expand Business Tier, select ADF Business Components and then View Link, and click OK.

  3. In the Create View Link wizard, on the Name page, supply a package and a component name.

  4. On the View Objects page, in the Select Source Attribute tree expand the source view object in the desired package. In the Select Destination Attribute tree expand the destination view object.

    For entity-based view objects, notice that in addition to the view object attributes, relevant associations also appear in the list.

  5. Select the same association in both Source and Destination trees. Then click Add to add the association to the table below.

    For example, Figure 5-30 shows the same EmpManagersFkAssoc association in both Source and Destination trees selected. The view link is self-referential because the definition of the association names the source and destination attribute on the same entity object (in this case, Employees).

    Figure 5-30 Master and Detail Related by a Self-Referential Association Selection

    Step 2 of the Create View Link wizard
  6. On the View Link Properties page, leave the default selections unchanged, but edit the accessor name of the destination accessor to provide a meaningful name.

    For example, Figure 5-31 shows the destination accessor has been renamed from EmployeesView to StaffList. This name will be exposed in the binding editor when the user interface developer populates the ADF Faces tree component by selecting this accessor. The name you provide will make clear to the UI developer the purpose of the accessor; in this case, to generate a list of employees associated with each manager.

    Figure 5-31 Renamed Destination Accessor in View LInk

    Step 3 of the Create View Link wizard
  7. Click Finish.

To define the view object instance in an existing application module:

  1. In the Application Navigator, double-click the application module.

  2. In the overview editor, click the Data Model navigation tab.

  3. In the Data Model page, expand the View Object Instances section and, in the Available View Objects list, select the view object definition that you defined the view criteria to filter.

    The New View Instance field below the list shows the name that will be used to identify the next instance of that view object that you add to the data model.

  4. To change the name before adding it, enter a different name in the New View Instance field.

  5. With the desired view object selected, shuttle the view object to the Data Model list.

    Figure 5-32 shows the view object EmployeesView has been renamed to Employees before it was shuttled to the Data Model list.

    Figure 5-32 Data Model Displays Added View Object Instance

    View object instance in the data model
  6. To filter the view object instance so that you specify the root value of the hierarchy, select the view object instance you added and click Edit.

  7. In the Edit View Instance dialog, shuttle the view criteria you created to the Selected list and enter the bind parameter value that corresponds to the root of the hierarchy.

    Figure 5-33 shows the view object ByEmployeeId view criteria with the bind parameter TheEmployeeId set to the value 100 corresponding to the employee that is at the highest level of the hierarchy.

    Figure 5-33 View Criteria Filters View Instance

    Edit View Instance dialog
  8. Click OK.

5.7.2 What Happens When You Create a Recursive Master-Detail Hierarchy

When you create an self-referential view link, JDeveloper creates the XML component definition file that represents its declarative settings and saves it in the directory that corresponds to the name of its package. This XML file contains the declarative information about the source and target attribute pairs that the association you selected specifies and contains the declarative information about the association that relates the source and target view object you selected.

Example 5-9 shows how the EmpManagerFkLink defines the same view object EmployeesView for the source and destination in its XML component definition file.

Example 5-9 Self-Referential View Link Defined in XML

<ViewLink
  xmlns="http://xmlns.oracle.com/bc4j"
  Name="EmpManagerFkLink"
  Version="11.1.1.53.5"
  EntityAssociation="test.model.EmpManagerFkAssoc">
  <ViewLinkDefEnd
    Name="EmployeesView1"
    Cardinality="1"
    Owner="test.model.EmployeesView"
    Source="true">
    <DesignTime>
      <Attr Name="_finderName" Value="ManagerIdEmployeesView"/>
      <Attr Name="_isUpdateable" Value="true"/>
    </DesignTime>
    <AttrArray Name="Attributes">
      <Item Value="test.model.EmployeesView.EmployeeId"/>
    </AttrArray>
  </ViewLinkDefEnd>
  <ViewLinkDefEnd
    Name="EmployeesView2"
    Cardinality="-1"
    Owner="test.model.EmployeesView">
    <DesignTime>
      <Attr Name="_finderName" Value="DirectReports"/>
      <Attr Name="_isUpdateable" Value="true"/>
    </DesignTime>
    <AttrArray Name="Attributes">
      <Item Value="test.model.EmployeesView.ManagerId"/>
    </AttrArray>
  </ViewLinkDefEnd>
</ViewLink>

In addition to saving the view link component definition itself, JDeveloper also updates the XML definition of the view object to add information about the view link accessor you've defined. As a confirmation of this, you can select the view object in the Application Navigator and inspect its details in the Structure window. As shown in Figure 5-34, you can see the defined accessor in the ViewLink Accessors node for the EmployeesView view object of the EmpManagerFkLink view link.

Figure 5-34 View Object with View Link Accessor in the Structure Window

Structure window showing view link accessor

5.8 Working with View Objects in Declarative SQL Mode

At runtime, when ADF Business Components works with JDBC to pass a query to the database and retrieve the result, the mechanism to retrieve the data is the SQL query. As an alternative to creating view objects that specify a SQL statement at design time, you can create entity-based view objects that contain no SQL statements. This capability of the ADF Business Components design time and runtime is known as declarative SQL mode. When the data model developer works with the wizard or editor for a view object in declarative SQL mode, they require no knowledge of SQL. In declarative SQL mode, the view object's metadata causes the ADF Business Components runtime to generate the SQL query statements as follows:

Additionally, the SQL statement that a declarative SQL mode view object generates at runtime will be determined by the SQL flavor specified in the Business Components page of the Project Properties dialog.


Note:

Currently, the supported flavors for runtime SQL generation are SQL92 (ANSI) style and Oracle style. For information about setting the SQL flavor for your project, see Section 3.3.1, "Choosing a Connection, SQL Flavor, and Type Map."


Declarative SQL mode selection is supported in JDeveloper as a setting that you can apply either to the entire data model project or to individual view objects that you create. The ADF Business Components design time also allows you to override the declarative SQL mode project-level setting for any view object you create.

The alternatives to declarative SQL mode are normal mode and expert mode. When you work in either of those modes, the view object definitions you create at design time always contain the entire SQL statement based on the SQL flavor required by your application module's defined database connection. Thus the capability of SQL independence does not apply to view objects that you create in normal or expert mode. For information about using the wizard and editor to customize view objects when SQL is desired at design time, see Section 5.2, "Populating View Object Rows from a Single Database Table."

5.8.1 How to Create SQL-Independent View Objects with Declarative SQL Mode

All view objects that you create in JDeveloper rely on the same design time wizard and editor. However, when you enable declarative SQL mode, the wizard and editor change to support customizing the view object definition without requiring you to display or enter any SQL. For example, the Query page of the Create View Object wizard with declarative SQL mode enabled lacks the Generated SQL field present in normal mode.

Additionally, in declarative SQL mode, since the wizard and editor do not allow you to enter WHERE and ORDERBY clauses, you provide equivalent functionality by defining a view criteria and sort criteria respectively. In declarative SQL mode, these criteria appear in the view object metadata definition and will be converted at runtime to their corresponding SQL clause. When the databound UI component has no need to display filtered or sorted data, you may omit the view criteria or sort criteria from the view object definition.

Otherwise, after you enable declarative SQL mode, the basic procedure to create a view object with ensured SQL independence is the same as you would follow to create any entity-based view object. For example, you must still ensure that your view object encapsulates the desired entity object metadata to support the intended runtime query. As with any entity-based view object, the columns of the runtime-generated FROM list must relate to the attributes of one or more of the view object's underlying entity objects. In declarative SQL mode, you automatically fulfill this requirement when working with the wizard or editor when you add or remove the attributes of the entity objects on the view object definition.

If you prefer to optimize the declarative SQL query so that the SELECT and FROM clauses of the SQL query statement are based solely on whether or not the attributes you add to the view object are rendered at runtime by a databound UI component, then you must disable the Selected in Query checkbox (sets IsSelected=false for the view object definition) for all added attributes. By default, the IsSelected property is true for any attribute that you add to the view object in declarative SQL mode. The default setting means the added attribute will be selected in the SQL statement regardless of whether or not the attribute is exposed by a databound UI component. When you create a new view object in declarative SQL mode, you can use the Attribute Settings page of the Create View Object wizard to change the setting for each attribute. If you need to alter this setting after you generate the view object, you can use the Property Inspector to change the Selected in Query property setting for one or more attributes that you select in the Attributes page of the view object editor.


Performance Tip:

A view object instance configured to generate SQL statements dynamically will requery the database during page navigation if a subset of all attributes with the same list of key entity objects is used in the subsequent page navigation. Thus performance can be improved by activating a superset of all the required attributes to eliminate a subsequent query execution.


Thus there are no unique requirements for creating entity-based view objects in declarative SQL mode, nor does declarative SQL mode sacrifice any of the runtime functionality of the normal mode counterpart. You can enable declarative SQL mode as a global preference so that it is the Create View Object wizard's default mode, or you can leave the setting disabled and select the desired mode directly in the wizard. The editor for a view object also lets you select and change the mode for an existing view object definition.

To enable declarative SQL mode for all new view objects:

  1. From the main menu, choose Tools > Preferences.

  2. In the Preferences dialog, expand the Business Components node and choose View Objects.

  3. On the Business Components: View Object page, select Enable Declarative SQL mode for new objects and click OK.

    To predetermine how the FROM list will be generated at runtime you can select Include all attributes in runtime-generated query, as described in Section 5.8.4, "How to Force Attribute Queries for Declarative SQL Mode View Objects."

To create an entity-based view object in declarative SQL mode, use the Create View Object wizard, which is available from the New Gallery.

Before you begin:

Create the desired entity objects as described in Section 4.2.1, "How to Create Multiple Entity Objects and Associations from Existing Tables."

To create declarative SQL-based view objects:

  1. In the Application Navigator, right-click the project in which you want to create the view objects and choose New.

  2. In the New Gallery, expand Business Tier, select ADF Business Components and then View Object, and click OK.

  3. On the Name page, enter a package name and a view object name. Keep the default setting Updatable access through entity objects enabled to indicate that you want this view object to manage data with its base entity object. Click Next.

    Any other choice for the data selection will disable declarative SQL mode in the Create View Object wizard.

  4. On the Entity Objects page, select the entity object whose data you want to use in the view object. Click Next.

    When you want to create a view object that joins entity objects, you can add secondary entity objects to the list. To create more complex entity-based view objects, see Section 5.5.1, "How to Create Joins for Entity-Based View Objects."

  5. On the Attributes page, select at least one attribute from the entity usage in the Available list and shuttle it to the Selected list. Attributes you do not select will not be eligible for use in view criteria and sort criteria. Click Next.

    You should select any attribute that you intend to customize (in the Attribute Settings page) or any attributes that you intend to use in a view criteria or sort criteria (in the Query page). Additionally, the tables that appear in the FROM list of the runtime-generated query will be limited to the tables corresponding to the attributes of the entity objects you select.

  6. On the Attribute Settings page, optionally, use the Select Attribute dropdown list to switch between the view object attributes in order to change their names or any of their initial settings.

  7. Use the Select Attribute dropdown list to switch between the previously selected view object attributes and deselect Selected in Query for each attribute that you want to be selected in the SQL statement based solely on whether or not the attribute is rendered by a databound UI component. Click Next.

    By default, the Selected in Query checkbox is enabled for all view object attributes that you add in declarative SQL mode. This default setting will generate a SQL statement with all added attributes selected. When you deselect the checkbox for an attribute, the IsSelected property is set to false and whether or not the attribute is selected will be determined at runtime by the databound UI component's usage of the attribute.

  8. On the Query page, select Declarative in the Query Mode dropdown list if it is not already displayed. The wizard changes to declarative SQL mode.

    If you did not select Enable declarative SQL mode for new objects, in the Preferences dialog, the wizard displays the default query mode, Normal. Changing the mode to Declarative in the wizard allows you to override the default mode for this single view object.

  9. Optionally, define Where and Order By criteria to filter and order the data as required. At runtime, ADF Business Components automatically generates the corresponding SQL statements based on the criteria you create.

    Click Edit next to the Where field to define the view criteria you will use to filter the data. The view criteria you enter will be converted at runtime to a WHERE clause that will be enforced on the query statement. For information about specifying view criteria, see Section 5.11, "Working with Named View Criteria."

    In the Order By field select the desired attribute in the Available list and shuttle it to the Selected list. Attributes you do not select will not appear in the SQL ORDERBY clause generated at runtime. Add additional attributes to the Selected list when you want the results to be sorted by more than one column. Arrange the selected attributes in the list according to their sort precedence. Then for each sort attribute, assign whether the sort should be performed in ascending or descending order. Assigning the sort order to each attribute ensures that attributes ignored by the UI component still follow the intended sort order.

    For example, as shown in Figure 5-35, to limit the CustomerCardStatus view object to display only the rows in the CUSTOMERS table for customers with a specific credit card code, the view criteria in the Where field limits the CardTypeCode attribute to a runtime-determined value. To order the data by customer ID and the customer's card expiration date, the Order By field identifies those attributes in the Selected list.

    Figure 5-35 Creating View Object Wizard, Query Page with Declarative Mode Selected

    Step 5 of Create View Object wizard in SI mode
  10. Click Finish.

5.8.2 How to Filter Declarative SQL-Based View Objects When Table Joins Apply

When you create an entity-based view object you can reference more than one entity object in the view object definition. In the case of view objects you create in declarative SQL mode, whether the base entity objects are activated from the view object definition will depend on the requirements of the databound UI component at runtime. If the UI component displays attribute values from multiple entity objects, then the SQL generated at runtime will contain a JOIN operation to query the appropriate tables.

Just as with any view object that you create, it is possible to filter the results from table joins by applying named view criteria. In the case of normal mode view objects, all entity objects and their attributes will be referenced by the view object definition and therefore will be automatically included in the view object's SQL statement. However, by delaying the SQL generation until runtime with declarative SQL mode, there is no way to know whether the view criteria should be applied.


Note:

In declarative SQL mode, you can define a view criteria to specify the WHERE clause (optional) when you create the view object definition. This type of view criteria when it exists will always be applied at runtime. For a description of this usage of the view criteria, see Section 5.8.1, "How to Create SQL-Independent View Objects with Declarative SQL Mode."


Because a SQL JOIN may not always result from a view object defined in declarative SQL mode with multiple entity objects, named view criteria that you define to filter query results should be applied conditionally at runtime. In other words, named view criteria that you create for declarative SQL-based view objects need not be applied as required, automatic filters. To support declarative SQL mode, named view criteria that you apply to a view object created in declarative SQL mode can be set to apply only on the condition that the UI component is bound to the attributes referenced by the view criteria. The named view criteria once applied will, however, support the UI component's need to display a filtered result set.

You use the Edit View Criteria dialog to create the named view criteria and enable its conditional usage by setting the appliedIfJoinSatisfied property in the Property Inspector.

To define a view criteria to filter only when the join is satisfied:

  1. Create the view object with declarative SQL mode enabled as described in Section 5.8.1, "How to Create SQL-Independent View Objects with Declarative SQL Mode."

  2. In the Application Navigator, double-click the view object.

  3. In the overview editor, click the Query navigation tab.

  4. In Query page, expand the View Criteria section, and click the Create new view criteria button.

  5. In the Create View Criteria dialog, create the view criteria as described in Section 5.11.1, "How to Create Named View Criteria Declaratively."

  6. After creating the view criteria, select it in the View Criteria section of Query page of the overview editor.

  7. With the view criteria selected, open the Property Inspector and set the AppliedIfJoinSatisfied property to true.

    The property value true means you want the view criteria to be applied only on the condition that the UI component requires the attributes referenced by the view criteria. The default value false means that the view criteria will automatically be applied at runtime. In the case of declarative SQL mode-based view objects, the value true ensures that the query filter will be appropriate to needs of the view object's databound UI component.

5.8.3 How to Filter Master-Detail Related View Objects with Declarative SQL Mode

Just as with normal mode view objects, you can link view objects that you create in declarative SQL mode to other view objects to form master-detail hierarchies of any complexity. The steps to create the view links are the same as with any other entity-based view object, as described in Section 5.6.2, "How to Create a Master-Detail Hierarchy for Entity-Based View Objects." However, in the case of view objects that you create in declarative SQL mode, you can further refine the view object results in the Source SQL or Destination SQL dialog for the view link by selecting a previously defined view criteria in the Create View Link wizard or the overview editor for the view link.

To define a view criteria for view link source or view link destination:

  1. Create the view objects in declarative SQL mode as described in Section 5.8.1, "How to Create SQL-Independent View Objects with Declarative SQL Mode."

  2. In the overview editor for the view objects, define the desired view criteria for either the source (master) view object or the destination (detail) view object as described in Section 5.8.2, "How to Filter Declarative SQL-Based View Objects When Table Joins Apply."

  3. Create the view link as described in Section 5.6.2, "How to Create a Master-Detail Hierarchy for Entity-Based View Objects" and perform one of these additional steps:

    • On the SQL Source page, select a previously defined view criteria to filter the master view object. Click Next.

    • On the Destination SQL page, select a previously defined view criteria to filter the detail view object.

      Figure 5-35 shows a view criteria that filters the master view object based on customer IDs.

    Figure 5-36 Filtering a View Link in Declarative SQL Mode

    Step 4 of Create View Link wizard
  4. After you create the view link, you can also select a previously defined view criteria. In the overview editor navigation list, select Query and expand the Source or Destination sections. In the View Criteria dropdown list, select the desired view criteria. The dropdown list will be empty if no view criteria exist for the view object.

    If the overview editor does not display a dropdown list for view criteria selection, then the view objects you selected for the view link were not created in declarative SQL mode. For view objects created in normal or expert mode, you must edit the WHERE clause to filter the data as required.

5.8.4 How to Force Attribute Queries for Declarative SQL Mode View Objects

Typically, when you define a declarative SQL mode view object, the attributes that get queried at runtime will be determined by the requirements of the databound UI component as it is rendered in the web page. This is the runtime-generation capability that makes view objects independent of the design time database's SQL flavor. However, you may also need to execute the view object programmatically without exposing it to an ADF data binding in the UI. In this case, you can enable the Include all attributes in runtime-generated query option to ensure that a programmatically executed view object has access to all of the entity attributes.


Note:

Be careful to limit the use of the Include all attributes in runtime-generated query option to programmatically executed view objects. If you expose the view object with this setting enabled to a databound UI component, the runtime query will include all attributes.


The Include all attributes in runtime-generated query option can be specified as a global preference setting or as a setting on individual view objects. Both settings may be used in these combinations:

  • Enable the global preference so that every view object you create includes all attributes in the runtime query statement.

  • Enable the global preference, but disable the setting on view objects that will not be executed programmatically and therefore should not include all attributes in the runtime query statement.

  • Disable the global preference (default), but enable the setting on view objects that will be executed programmatically and therefore should include all attributes in the runtime query statement.

To set the global preference to include all attributes in the query:

  1. From the main menu, choose Tools > Preferences.

  2. In the Preferences dialog, expand Business Components and select View Objects.

  3. On the Business Components: View Object page, select Enable Declarative SQL mode for new objects.

  4. Select Include all attributes in runtime-generated query to force all attributes of the view object's underlying entity objects to participate in the query and click OK.

    Enabling this option sets a flag in the view object definition but you will still need to add entity object selections and entity object attribute selections to the view object definition.

You can change the view object setting in the Tuning section of the overview editor's General page. The overview editor only displays the Include all attributes in runtime-generated query option if you have created the view object in declarative SQL mode.

To set the view object-specific preference to include all attributes in the query:

  1. When you want to force all attributes for specific view objects, create the view object in the Create View Object wizard and be sure that you have enabled declarative SQL mode.

    You can verify this in the overview editor. In the overview editor, click the Query navigation tab and click the Edit SQL Query button along the top of the page. In the Edit Query dialog, verify that the SQL Mode dropdown list shows the selection Declarative.

  2. In the overview editor, click the General navigation tab.

  3. In the General page, expand the Tuning section and select Include all attributes in runtime-generated query.

    Enabling this option forces all attributes of the view object's underlying entity objects to participate in the query. When enabled, it sets a flag in the view object definition but you will still need to add entity object selections and entity object attribute selections to the view object definition.

5.8.5 What Happens When You Create a View Object in Declarative SQL Mode

When you create the view object in declarative SQL mode, three properties get added to the view object's metadata: SelectListFlags, FromListFlags, and WhereFlags. Properties that are absent in declarative SQL mode are the normal mode view object's SelectList, FromList, and Where properties, which contain the actual SQL statement (or, for expert mode, the SQLQuery element). Example 5-10 shows the three view object metadata flags that get enabled in declarative SQL mode to ensure that SQL will be generated at runtime instead of specified as metadata in the view object's definition.

Example 5-10 View Object Metadata with Declarative SQL Mode Enabled

<ViewObject
  xmlns="http://xmlns.oracle.com/bc4j"
  Name="CustomerCardStatus"
  SelectListFlags="1"
  FromListFlags="1"
  WhereFlags="1"
   ...

Similar to view objects that you create in either normal or expert mode, the view object metadata also includes a ViewAttribute element for each attribute that you select in the Attribute page of the Create View Object wizard. However, in declarative SQL mode, when you "select" attributes in the wizard (or add an attribute in the overview editor), you are not creating a FROM or SELECT list in the design time. The attribute definitions that appear in the view object metadata only determine the list of potential entities and attributes that will appear in the runtime-generated statements. For information about how ADF Business Components generates these SQL lists, see Section 5.8.6, "What Happens at Runtime: When a Declarative SQL Mode Query is Generated."

Example 5-11 shows the additional features of declarative SQL mode view objects, including the optional declarative WHERE clause (DeclarativeWhereClause element) and the optional declarative ORDERBY clause (SortCriteria element).

Example 5-11 View Object Metadata: Declarative View Criteria and Sort Criteria

<DeclarativeWhereClause>
    <ViewCriteria
        Name="CustomerStatusWhereCriteria"
        ViewObjectName="oracle.fodemo.storefront.store.queries.CustomerCardStatus"
        Conjunction="AND"
        Mode="3"
        AppliedIfJoinSatisfied="false">
        <ViewCriteriaRow
            Name="vcrow60">
            <ViewCriteriaItem
                Name="CardTypeCode"
                ViewAttribute="CardTypeCode"
                Operator="STARTSWITH"
                Conjunction="AND"
                Required="Optional">
            <ViewCriteriaItemValue
                Value=":cardtype"
                IsBindVarValue="true"/>
            </ViewCriteriaItem>
        </ViewCriteriaRow>
    </ViewCriteria>
    </DeclarativeWhereClause>
    <SortCriteria>
        <Sort
        Attribute="CustomerId"/>
    <Sort
        Attribute="CardTypeCode"/>
    </SortCriteria>

5.8.6 What Happens at Runtime: When a Declarative SQL Mode Query is Generated

At runtime, when a declarative SQL mode query is generated, ADF Business Components determines which attributes were defined from the metadata ViewCriteria element and SortCriteria element. It then uses these attributes to generate the WHERE and ORDERBY clauses. Next, the runtime generates the FROM list based on the tables corresponding to the entity usages defined by the metadata ViewAttribute elements. Finally, the runtime builds the SELECT statement based on the attribute selection choices the end user makes in the UI. As a result, the view object in declarative SQL mode generates all SQL clauses entirely at runtime. The runtime-generated SQL statements will be based on the flavor that appears in the project properties setting. Currently, the runtime supports SQL92 (ANSI) style and Oracle style flavors.

5.8.7 What You May Need to Know About Overriding Declarative SQL Mode Defaults

JDeveloper lets you control declarative SQL mode for all new view objects you add to your data model project or for individual view objects you create or edit. These settings may be used in these combinations:

  • Enable the global preference in the Preferences dialog (select Tools > Preferences). Every view object you create will delay SQL generation until runtime. Figure 5-37 shows the global preference Enable declarative SQL for new objects set to enabled.

  • Enable the global preference in the Preferences dialog, but change the SQL mode for individual view objects. In this case, unless you change the SQL mode, the view objects you create will delay SQL generation until runtime.

  • Disable the global preference (default) in the Preferences dialog, but select declarative SQL mode for individual view objects. In this case, unless you change the SQL mode, view objects you create will contain SQL statements.

Figure 5-37 Preferences Dialog with Declarative SQL Mode Enabled

View object preferences dialog

To edit the SQL mode for a view object you have already created, open the Query page in the Edit Query dialog and select Declarative from the SQL Mode dropdown list. To display the Edit Query dialog, open the view object in the overview editor, select Query from the navigation list and click the Edit SQL Query button. The same option appears in the Query page of the Create View Object wizard.

5.8.8 What You May Need to Know About Working Programmatically with Declarative SQL Mode View Objects

As a convenience to developers, the view object implementation API allows individual attributes to be selected and deselected programmatically. This API may be useful in combination with the view objects you create in declarative SQL mode and intend to execute programmatically. Example 5-12 shows how to call selectAttributeDefs() on the view object when you want to add a subset of attributes to those already configured with SQL mode enabled.

Example 5-12 ViewObjectImpl API with SQL Mode View Objects

ApplicationModule am = Configuration.createRootApplicationModule(amDef, config);
ViewObjectImpl vo = (ViewObjectImpl) am.findViewObject("CustomerVO");
vo.resetSelectedAttributeDefs(false);
vo.selectAttributeDefs(new String[] {"FirstName, "LastName"});
vo.executeQuery();

The call to selectAttributeDefs() adds the attributes in the array to a private member variable of ViewObjectImpl. A call to executeQuery() transfers the attributes in the private member variable to the actual select list. It is important to understand that these ViewObjectImpl attribute calls are not applicable to the client layer and are only accessible inside the Impl class of the view object on the middle tier.

Additionally, you might call unselectAttributeDefs() on the view object when you want to deselect a small subset of attributes after enabling the Include all attributes in runtime-generated query option. Alternatively, you can call selectAttributeDefs() on the view object to select a small subset of attributes after disabling the Include all attributes in runtime-generated query option.


Caution:

Be careful not to expose a declarative SQL mode view object executed with this API to the UI since only the value of the Include all attributes in runtime-generated query option will be honored.


5.9 Working with View Objects in Expert Mode

When defining entity-based view objects, you can fully specify the WHERE and ORDER BY clauses, whereas, by default, the FROM clause and SELECT list are automatically derived. The names of the tables related to the participating entity usages determine the FROM clause, while the SELECT list is based on the:

When you require full control over the SELECT or FROM clause in a query, you can enable expert mode.


Tips:

The view object editors and wizard in the JDeveloper provide full support for generating SQL from choices that you make. For example, two such options allow you to declaratively define outer joins and work in declarative SQL mode (where no SQL is generated until runtime).


5.9.1 How to Customize SQL Statements in Expert Mode

To enable expert mode, select Expert Mode from the SQL Mode dropdown list on the Query panel of the Create View Object wizard. You can also modify the SQL statement of an existing entity-based view object in the view object overview editor. In the overview editor, navigate to the Query page and click the Edit SQL Query button. In the Edit Query dialog, select Expert Mode from the SQL Mode dropdown list.

5.9.2 How to Name Attributes in Expert Mode

If your SQL query includes a calculated expression, use a SQL alias to assist the Create View Object wizard in naming the column with a Java-friendly name. Example 5-13 shows a SQL query that includes a calculated expression.

Example 5-13 SQL Query with Calculated Expression

select PERSON_ID, EMAIL, 
       SUBSTR(FIRST_NAME,1,1)||'. '||LAST_NAME
from PERSONS
order by EMAIL

Example 5-14 uses a SQL alias USER_SHORT_NAME to assist the Create View Object wizard in naming the column with a Java-friendly name. The wizard will display UserShortName as the name of the attribute derived from this calculated expression.

Example 5-14 SQL Query with SQL Alias

select PERSON_ID, EMAIL, 
       SUBSTR(FIRST_NAME,1,1)||'. '||LAST_NAME AS USER_SHORT_NAME
from PERSONS
order by EMAIL

5.9.3 What Happens When You Enable Expert Mode

When you enable expert mode, the read-only Generated Statement section of the Query page becomes a fully editable Query Statement text box, displaying the full SQL statement. Using this text box, you can change every aspect of the SQL query.

For example, Figure 5-38 shows the Query page of the Edit Query dialog for the OrderItems view object. It's an expert mode, entity-based view object that references a PL/SQL function decode that obtains its input values from an expression set on the ShippingCost attribute.

Figure 5-38 OrderItems Expert Mode View Object

Edit Query dialog

5.9.4 What You May Need to Know About Expert Mode

When you define a SQL query using expert mode in the Edit Query dialog, you type a SQL language statement directly into the editor. Using this mode places some responsibility on the Business Components developer to understand how the view object handles the metadata resulting from the query definition. Review the following information to familiarize yourself with the behavior of the Edit Query dialog that you use in expert mode.

5.9.4.1 Expert Mode Provides Limited Attribute Mapping Assistance

The automatic cooperation of a view object with its underlying entity objects depends on correct attribute-mapping metadata saved in the XML component definition. This information relates the view object attributes to corresponding attributes from participating entity usages. JDeveloper maintains this attribute mapping information in a fully automatic way for normal entity-based view objects. However, when you decide to use expert mode with a view object, you need to pay attention to the changes you make to the SELECT list. That is the part of the SQL query that directly relates to the attribute mapping. Even in expert mode, JDeveloper continues to offer some assistance in maintaining the attribute mapping metadata when you do the following to the SELECT list:

  • Reorder an expression without changing its column alias

    JDeveloper reorders the corresponding view object attribute and maintains the attribute mapping.

  • Add a new expression

  • JDeveloper adds a new SQL-calculated view object attribute with a corresponding camel-capped name based on the column alias of the new expression.

  • Remove an expression

    JDeveloper converts the corresponding SQL-calculated or entity-mapped attribute related to that expression to a transient attribute.

However, if you rename a column alias in the SELECT list, JDeveloper has no way to detect this, so it is treated as if you removed the old column expression and added a new one of a different name.

After making any changes to the SELECT list of the query, visit the Attribute Mappings page to ensure that the attribute-mapping metadata is correct. The table on this page, which is disabled for view objects in normal mode, becomes enabled for expert mode view objects. For each view object attribute, you will see its corresponding SQL column alias in the table. By clicking into a cell in the View Attributes column, you can use the dropdown list that appears to select the appropriate entity object attribute to which any entity-mapped view attributes should correspond.


Note:

If the view attribute is SQL-calculated or transient, a corresponding attribute with a "SQL" icon appears in the View Attributes column to represent it. Since neither of these type of attributes are related to underlying entity objects, there is no entity attribute related information required for them.


5.9.4.2 Expert Mode Drops Custom Edits

When you disable expert mode for a view object, it will return to having its SELECT and FROM clause be derived again. JDeveloper warns you that doing this might cause your custom edits to the SQL statement to be lost. If this is what you want, after acknowledging the alert, your view object's SQL query reverts back to the default.

5.9.4.3 Expert Mode Ignores Changes to SQL Expressions

Consider a Products view object with a SQL-calculated attribute named Shortens whose SQL expression you defined as SUBSTR(NAME,1,10). If you switch this view object to expert mode, the Query Statement box will show a SQL query similar to the one shown in Example 5-15.

Example 5-15 SQL-Calculated Attribute Expression in Expert Mode

SELECT Products.PROD_ID, 
       Products.NAME, 
       Products.IMAGE, 
       Products.DESCRIPTION, 
       SUBSTR(NAME,1,10) AS SHORT_NAME
FROM PRODUCTS Products

If you go back to the attribute definition for the Shortens attribute and change the SQL Expression field from SUBSTR(NAME,1,10) to SUBSTR(NAME,1,15), then the change will be saved in the view object's XML component definition. Note, however, that the SQL query in the Query Statement box will remain as the original expression. This occurs because JDeveloper never tries to modify the text of an expert mode query. In expert mode, the developer is in full control. JDeveloper attempts to adjust metadata as a result of some kinds of changes you make yourself to the expert mode SQL statement, but it does not perform the reverse. Therefore, if you change view object metadata, the expert mode SQL statement is not updated to reflect it.

Therefore, you need to update the expression in the expert mode SQL statement itself. To be completely thorough, you should make the change both in the attribute metadata and in the expert mode SQL statement. This would ensure — if you (or another developer on your team) ever decides to toggle expert mode off at a later point in time — that the automatically derived SELECT list would contain the correct SQL-derived expression.


Note:

If you find you had to make numerous changes to the view object metadata of an expert mode view object, you can avoid having to manually translate any effects to the SQL statement by copying the text of your customized query to a temporary backup file. Then, you can disable expert mode for the view object and acknowledge the warning that you will lose your changes. At this point JDeveloper will rederive the correct generated SQL statement based on all the new metadata changes you've made. Finally, you can enable expert mode once again and reapply your SQL customizations.


5.9.4.4 Expert Mode Returns Error for SQL Calculations that Change Entity Attributes

When changing the SELECT list expression that corresponds to entity-mapped attributes, don't introduce SQL calculations into SQL statements that change the value of the attribute when retrieving the data. To illustrate the problem that will occur if you do this, consider the query for a simple entity-based view object named Products shown in Example 5-16.

Example 5-16 Query Statement Without SQL-Calculated Expression

SELECT Products.PROD_ID, 
       Products.NAME, 
       Products.IMAGE, 
       Products.DESCRIPTION
FROM PRODUCTS Products

Imagine that you wanted to limit the name column to display only the first ten characters of the name of a product query. The correct way to do that would be to introduce a new SQL-calculated field, such as ShortName with an expression like SUBSTR(Products.NAME,1,10). One way you should avoid doing this is to switch the view object to expert mode and change the SELECT list expression for the entity-mapped NAME column to the include the SQL-calculate expression, as shown in Example 5-17.

Example 5-17 Query Statement With SQL-Calculated Expression

SELECT Products.PROD_ID, 
       SUBSTR(Products.NAME,1,10) AS NAME, 
       Products.IMAGE, 
       Products.DESCRIPTION
FROM PRODUCTS Products

This alternative strategy would initially appear to work. At runtime, you see the truncated value of the name as you are expecting. However, if you modify the row, when the underlying entity object attempts to lock the row it does the following:

  • Issues a SELECT FOR UPDATE statement, retrieving all columns as it tries to lock the row.

  • If the entity object successfully locks the row, it compares the original values of all the persistent attributes in the entity cache as they were last retrieved from the database with the values of those attributes just retrieved from the database during the lock operation.

  • If any of the values differs, then the following error is thrown:

    (oracle.jbo.RowInconsistentException) 
    JBO-25014: Another user has changed the row with primary key [...]
    

If you see an error like this at runtime even though you are the only user testing the system, it is most likely due to your inadvertently introducing a SQL function in your expert mode view object that changed the selected value of an entity-mapped attribute. In Example 5-17, the SUBSTR(Products.NAME,1,10) function introduced causes the original selected value of the Name attribute to be truncated. When the row-lock SQL statement selects the value of the NAME column, it will select the entire value. This will cause the comparison shown in Example 5-17 to fail, producing the "phantom" error that another user has changed the row.

The same thing would happen with NUMBER-valued or DATE-valued attributes if you inadvertently apply SQL functions in expert mode to truncate or alter their retrieved values for entity-mapped attributes.

Therefore, if you need to present altered versions of entity-mapped attribute data, introduce a new SQL-calculated attribute with the appropriate expression to handle the task.

5.9.4.5 Expert Mode Retains Formatting of SQL Statement

When you change a view object to expert mode, its XML component definition changes from storing parts of the query in separate XML attributes, to saving the entire query in a single <SQLQuery> element. The query is wrapped in an XML CDATA section to preserve the line formatting you may have done to make a complex query be easier to understand.

5.9.4.6 Expert Mode Wraps Queries as Inline Views

If your expert-mode view object:

  • Contains a ORDERBY clause specified in the Order By field of the Query Clauses page at design time, or

  • Has a dynamic WHERE clause or ORDERBY clause applied at runtime using setWhereClause() or setOrderByClause()

then its query gets nested into an inline view before applying these clauses. For example, suppose your expert mode query was defined like the one shown in Example 5-18.

Example 5-18 Expert Mode Query Specified At Design Time

select PERSON_ID, EMAIL, FIRST_NAME, LAST_NAME
from PERSONS 
union all
select PERSON_ID, EMAIL, FIRST_NAME, LAST_NAME
from INACTIVE_PERSONS

Then, at runtime, when you set an additional WHERE clause like email = :TheUserEmail, the view object nests its original query into an inline view like the one shown in Example 5-19.

Example 5-19 Runtime-Generated Query With Inline Nested Query

SELECT * FROM(
select PERSON_ID, EMAIL, FIRST_NAME, LAST_NAME
from PERSONS 
union all
select PERSON_ID, EMAIL, FIRST_NAME, LAST_NAME
from INACTIVE_PERSONS) QRSLT

And, the view object adds the dynamic WHERE clause predicate at the end, so that the final query the database sees looks like the one shown in Example 5-20.

Example 5-20 Runtime-Generated Query With Dynamic WHERE Clause

SELECT * FROM(
select PERSON_ID, EMAIL, FIRST_NAME, LAST_NAME
from PERSONS 
union all
select PERSON_ID, EMAIL, FIRST_NAME, LAST_NAME
from INACTIVE_PERSONS) QRSLT
WHERE email = :TheUserEmail

This query "wrapping" is necessary in general for expert mode queries, because the original query could be arbitrarily complex, including SQL UNION, INTERSECT, MINUS, or other operators that combine multiple queries into a single result. In those cases, simply "gluing" the additional runtime WHERE clause onto the end of the query text could produce unexpected results. For example, the clause might apply only to the last of several UNION'ed statements. By nesting the original query verbatim into an inline view, the view object guarantees that your additional WHERE clause is correctly used to filter the results of the original query, regardless of how complex it is.

5.9.4.7 Limitation of Inline View Wrapping at Runtime

Inline view wrapping of expert mode view objects, limits a dynamically added WHERE clause to refer only to columns in the SELECT list of the original query. To avoid this limitation, when necessary you can disable the use of the inline view wrapping by calling setNestedSelectForFullSql(false).

5.9.4.8 Expert Mode Changes May Affect Dependent Objects

When you modify a view object query to be in expert mode after you have already created the view links that involve that view object or after you created other view objects that extend the view object, JDeveloper will warn you with the alert shown in Figure 5-39. The alert reminds you that you should revisit these dependent components to ensure their SQL statements still reflect the correct query.

Figure 5-39 Proactive Reminder to Revisit Dependent Components

Dependent components dialog reminder

For example, if you were to modify the OrdersVO view object to use expert mode, because the OrdersByStatusVO view object extends it, you need to revisit the extended component to ensure that its query still logically reflects an extension of the modified parent component.

5.10 Working with Bind Variables

Bind variables provide you with the means to supply attribute values at runtime to the view object or view criteria. All bind variables are defined at the level of the view object and used in one of the following ways:

Bind variables that you add to a WHERE clause require a valid value at runtime, or a runtime exception error will be thrown. In contrast, view criteria execution need not require the bind variable value if the view criteria item for which the bind variable is assigned is not required. To enforce this desired behavior, the Bind Variable dialog lets you can specify whether a bind variable is required or not.

You can define a default value for the bind variable or write scripting expressions for the bind variable that includes dot notation access to attribute property values. Expressions are based on the Groovy scripting language, as described in Section 3.6, "Overview of Groovy Support."

5.10.1 How to Add Bind Variables to a View Object Definition

To add a named bind variable to a view object, use the Query page of the overview editor for the view object. You can define as many bind variables as you need.

Before you begin:

Create the desired view objects as described in Section 5.2.1, "How to Create an Entity-Based View Object," and Section 5.2.3, "How to Create an Expert Mode, Read-Only View Object."

To define a named bind variable:

  1. In the Application Navigator, double-click the view object.

  2. In the overview editor, click the Query navigation tab.

  3. In the Query page, expand the Bind Variables section and click the Create new bind variable button.

  4. In the Bind Variable dialog, enter the name and data type for the new bind variable.

    Because the bind variables share the same namespace as view object attributes, specify names that don't conflict with existing view object attribute names. As with view objects attributes, by convention bind variable names are created with an initial capital letter, but you can rename it as desired.

  5. Optionally, specify a default value for the bind variable:

    • When you want the value to be determined at runtime using an expression, enter a Groovy scripting language expression, select the Expression value type and enter the expression in the Value field. Optionally, click Edit to open the Expression dialog. The Expression dialog gives you a larger text area to write the expression. For example, you might want to define a bind variable to filter view instances based on the current user, as described in Section 5.10.2, "How to Reference the Current User in a Named Bind Variable Using Groovy."

    • When you want to define a default value, select the Literal value type and enter the literal value in the Value field.

  6. Decide on one of the following runtime usages for the bind variable:

    • When you want the value to be supplied to a SQL WHERE clause using a bind variable in the clause, select the Required checkbox. This ensures that a runtime exception will be thrown if the value is not supplied. For more information, see Section 5.10.8.2, "Errors Related to Naming Bind Variables."

    • When you want the value to be supplied to a view criteria using a bind variable in the view criteria, only select the Required checkbox when you need to reference the same bind variable in a SQL WHERE clause or when you want to use the bind variable as the assigned value of a view criteria item that is specifically defined as required by a view criteria that is applied to a view object. When Required is unselected this ensures that the value is optional and that no runtime exception will be thrown if the bind variable is not resolved. For example, view criteria with bind variables defined can be used to create Query-by-Example search forms in the user interface. For more information, see Section 5.11, "Working with Named View Criteria."

  7. Select the Control Hints tab and specify control hints like Label Text, Format Type, Format mask, and others.

    The view layer will use bind variable control hints when you build user interfaces like search pages that allow the user to enter values for the named bind variables. The Updatable checkbox controls whether the end user will be allowed to change the bind variable value through the user interface. If a bind variable is not updatable, then its value can only be changed programmatically by the developer.

  8. Click OK.

After defining the bind variables, the next step is to reference them in the SQL statement. While SQL syntax allows bind variables to appear both in the SELECT list and in the WHERE clause, you'll typically use them in the latter context, as part of your WHERE clause. For example, Example 5-21 shows the bind variables LowUserId and HighUserId introduced into a SQL statement created using the Query page in the overview editor for the view object.

Example 5-21 Bind Variables in the WHERE Clause of View Object SQL Statement

select PERSON_ID, EMAIL, FIRST_NAME, LAST_NAME
from PERSONS
where (upper(FIRST_NAME) like upper(:TheName)||'%'
   or  upper(LAST_NAME)  like upper(:TheName)||'%')
  and PERSON_ID between :LowUserId and :HighUserId
order by EMAIL

Notice that you reference the bind variables in the SQL statement by prefixing their name with a colon like :TheName or :LowUserId. You can reference the bind variables in any order and repeat them as many times as needed within the SQL statement.

5.10.2 How to Reference the Current User in a Named Bind Variable Using Groovy

You can use the Groovy expression adf.context.securityContext.userName to set the default value for the named bind variable that you use to provide the current user in a view instance filter. Specifically, you can use the bind variable in a named view criteria that you define to filter a view object instance in the data model for the project. For example, in the StoreFront module of the Fusion Order Demo application, the named bind variable userPrincipal is defined for the PersonsVO view object, as shown in Figure 5-40.

Figure 5-40 Groovy Expression Used to Set userPrincipal Bind Variable

Bind Variable dialog with user name expression

The PersonsVO view object also defines the AuthenticatedUserByPrincipalCriteria view criteria. This view criteria defines a filter for the PrincipalName attribute of the PersonsVO with the bind variable userPrincipal providing the value. In this example, the bind variable userPrincipal is defined with Updatable enabled. This ensures that the view criteria is able to set the value obtained at runtime from the ADF security context. Since the bind variable is not used in the SQL WHERE clause for the PersonsVO view object, the Required field is unselected. This ensures that the value is optional and that no runtime exception will be thrown if the bind variable is not resolved.

Then in the data model for the StoreFrontService project, where the PersonsVO specifies the view definition for the usage AuthenticatedUser, the view criteria AuthenticatedUserByPrincipalCriteria with the named bind variable is defined as the view usage's runtime filter. For details about creating view instances for your project's data model, see Section 9.2.3.3, "Customizing a View Object Instance that You Add to an Application Module."

5.10.3 What Happens When You Add Named Bind Variables

Once you've added one or more named bind variables to a view object, you gain the ability to easily see and set the values of these variables at runtime. Information about the name, type, and default value of each bind variable is saved in the view object's XML component definition file. If you have defined UI control hints for the bind variables, this information is saved in the view object's component message bundle file along with other control hints for the view object.

5.10.4 How to Test Named Bind Variables

The Business Component Browser allows you to interactively inspect and change the values of the named bind variables for any view object, which can really simplify experimenting with your application module's data model when named bind parameters are involved. For more information about editing the data model and running the Business Component Browser, see Section 6.3, "Testing View Object Instances Using the Business Component Browser."

The first time you execute a view object in the Business Component Browser to display the results in the data view page, a Bind Variables dialog will appear, as shown in Figure 5-41.

The Bind Variables dialog lets you:

  • View the name, as well as the default and current values, of the particular bind variable you select from the list

  • Change the value of any bind variable by updating its corresponding Value field before clicking OK to set the bind variable values and execute the query

  • Inspect and set the bind variables for the view object in the current data view page, using the Edit Bind Parameters button in the toolbar — whose icon looks like ":id"

  • Verify control hints are correctly set up by showing the label text hint in the Bind Variables list and by formatting the Value attribute using the respective format mask

Figure 5-41 Setting Bind Variables in the Business Component Browser

Bind Variables tester

If you defined the bind variable in the Bind Variables dialog with the Reference checkbox deselected (the default), you will be able to test view criteria and supply the bind variable with values as needed. Otherwise, if you selected the Reference checkbox, then you must supply a value for the bind variable in the Business Component Browser. The Business Component Browser will throw the same exception seen at runtime for any view object whose SQL statement use bind variables that do not resolve with a supplied value.

5.10.5 How to Add a WHERE Clause with Named Bind Variables at Runtime

Using the view object's setWhereClause() method, you can add an additional filtering clause at runtime. This runtime-added WHERE clause predicate does not replace the design-time generated predicate, but rather further narrows the query result by adding to the existing design time WHERE clause. Whenever the dynamically added clause refers to a value that might change during the life of the application, you should use a named bind variable instead of concatenating the literal value into the WHERE clause predicate.

For example, assume you want to further filter the PersonList view object at runtime based on the value of the PERSON_TYPE_CODE column in the table. Also assume that you plan to search sometimes for rows where PERSON_TYPE_CODE = 'CUST' and other times for rows where PERSON_TYPE_CODE = 'SUPP'. While slightly fewer lines of code, Example 5-22 is not desirable because it changes the WHERE clause twice just to query two different values of the same PERSON_TYPE_CODE column.

Example 5-22 Incorrect Use of setWhereClause() Method

// Don't use literal strings if you plan to change the value!
vo.setWhereClause("person_type_code = 'CUST'");
// execute the query and process the results, and then later...
vo.setWhereClause("person_type_code = 'person'");

Instead, you should add a WHERE clause predicate that references named bind variables that you define at runtime as shown in Example 5-23.

Example 5-23 Correct Use of setWhereClause() Method and Bind Variable

vo.setWhereClause("person_type_code = :ThePersonType");
vo.defineNamedWhereClauseParam("ThePersonType", null, null);
vo.setNamedWhereClauseParam("ThePersonType","CUST");
// execute the query and process the results, and then later...
vo.setNamedWhereClauseParam("ThePersonType","person");

This allows the text of the SQL statement to stay the same, regardless of the value of PERSON_TYPE_CODE you need to query on. When the query text stays the same across multiple executions, the database will return the results without having to reparse the query.

If you later need to remove the dynamically added WHERE clause and bind variable, you should do so the next time you need them to be different, just before executing the query. This will prevent the type of SQL execution error as described in Section 5.10.8.1, "An Error Related to Clearing Bind Variables." Avoid calling removeNamedWhereClauseParam() in your code immediately after setting the WHERE clause.

An updated test client class illustrating these techniques would look like what you see in Example 5-24. In this case, the functionality that loops over the results several times has been refactored into a separate executeAndShowResults() method. The program first adds an additional WHERE clause of person_id = :ThePersonId and then later replaces it with a second clause of person_type_code = :ThePersonType.

Example 5-24 TestClient Program Exercising Named Bind Variable Techniques

package devguide.examples.readonlyvo.client;

import oracle.jbo.ApplicationModule;
import oracle.jbo.Row;
import oracle.jbo.ViewObject;
import oracle.jbo.client.Configuration;
import oracle.jbo.domain.Number;

public class TestClientBindVars {
  public static void main(String[] args) {
    String        amDef = "devguide.examples.readonlyvo.PersonService";
    String        config = "PersonServiceLocal";
    ApplicationModule am =
     Configuration.createRootApplicationModule(amDef,config);
    ViewObject vo = am.findViewObject("PersonList");
    // Set the two design time named bind variables
    vo.setNamedWhereClauseParam("TheName","shelli%");
    vo.setNamedWhereClauseParam("HighUserId", new Number(215));
    executeAndShowResults(vo);
    // Add an extra where clause with a new named bind variable
    vo.setWhereClause("person_type_code = :ThePersonId");
    vo.defineNamedWhereClauseParam("ThePersonId", null, null);
    vo.setNamedWhereClauseParam("ThePersonId",new Number(116));
    executeAndShowResults(vo);
    vo.removeNamedWhereClauseParam("ThePersonId");
    // Add an extra where clause with a new named bind variable
    vo.setWhereClause("person_type_code = :ThePersonType");
    vo.defineNamedWhereClauseParam("ThePersonType", null, null);
    vo.setNamedWhereClauseParam("ThePersonType","SUPP");
    // Show results when :ThePersonType = 'SUPP'
    executeAndShowResults(vo);
    vo.setNamedWhereClauseParam("ThePersonType","CUST");
    // Show results when :ThePersonType = 'CUST'
    executeAndShowResults(vo);
    Configuration.releaseRootApplicationModule(am,true);
  }  
  private static void executeAndShowResults(ViewObject vo) {
    System.out.println("---");
    vo.executeQuery();
    while (vo.hasNext()) {
      Row curUser = vo.next();
      System.out.println(curUser.getAttribute("PersonId")+" "+
                         curUser.getAttribute("ShortName"));
    }    
  }
}

However, if you run this test program, you may actually get a runtime error like the one shown in Example 5-25.

Example 5-25 Runtime Error Resulting From a SQL Parsing Error

oracle.jbo.SQLStmtException: JBO-27122: SQL error during statement preparation.
Statement: 
SELECT * FROM (select PERSON_ID, EMAIL, FIRST_NAME, LAST_NAME
from PERSONS 
where (upper(FIRST_NAME) like upper(:TheName)||'%'
   or  upper(LAST_NAME)  like upper(:TheName)||'%')
  and PERSON_ID between :LowUserId and :HighUserId
order by EMAIL) QRSLT  WHERE (person_type_code = :ThePersonType)
## Detail 0 ##
java.sql.SQLException: ORA-00904: "PERSON_TYPE": invalid identifier

The root cause, which appears after the ## Detail 0 ## in the stack trace, is a SQL parsing error from the database reporting that PERSON_TYPE_CODE column does not exist even though the PERSONS table definitely has a PERSON_TYPE_CODE column. The problem occurs due to the mechanism that view objects use by default to apply additional runtime WHERE clauses on top of read-only queries. Section 5.10.7, "What Happens at Runtime: When a Read-Only View Object WHERE Clause is Set," explains a resolution for this issue.

5.10.6 How to Set Existing Bind Variable Values at Runtime

To set named bind variables at runtime, use the setNamedWhereClauseParam() method on the ViewObject interface. In JDeveloper, you can choose Refactor > Duplicate to create a new TestClientBindVars class based on the existing TestClient.java class as shown in Section 6.4.2, "How to Create a Command-Line Java Test Client." In the test client class, you can set the values of the bind variables using a few additional lines of code. For example, the setNamedWhereClauseParam() might take as arguments the bind variables HighUserId and TheName as shown in Example 5-26.

Example 5-26 Setting the Value of Named Bind Variables Programmatically

// changed lines in TestClient class 
ViewObject vo = am.findViewObject("PersonList");
vo.setNamedWhereClauseParam("TheName","alex%");
vo.setNamedWhereClauseParam("HighUserId", new Number(315));
vo.executeQuery();
// etc.

Running the test client class shows that your bind variables are filtering the data. For example, the resulting rows for the setNamedWhereClauseParam() method shown in Example 5-26 may show only two matches based on the name alex as shown in Example 5-27.

Example 5-27 Result of Bind Variables Filtering the Data in TestClient Class

303 ahunold
315 akhoo

Whenever a view object's query is executed, you can view the actual bind variable values in the runtime debug diagnostics like the sample shown in Example 5-28.

Example 5-28 Debug Diagnostic Sample With Bind Variable Values

[256] Bind params for ViewObject: PersonList
[257] Binding param "LowUserId": 0
[258] Binding param "HighUserId": 315
[259] Binding param "TheName": alex%

This information that can be invaluable when debugging your applications. Notice that since the code did not set the value of the LowUserId bind variable, it took on the default value of 0 (zero) specified at design time. Also notice that the use of the UPPER() function in the WHERE clause and around the bind variable ensured that the match using the bind variable value for TheName was performed case-insensitively. The sample code set the bind variable value to "alex%" with a lowercase "a", and the results show that it matched Alexander.

5.10.7 What Happens at Runtime: When a Read-Only View Object WHERE Clause is Set

If you dynamically add an additional WHERE clause at runtime to a read-only view object, its query gets nested into an inline view before applying the additional WHERE clause.

For example, suppose your query was defined as shown in Example 5-29.

Example 5-29 Query Specified At Design Time

select PERSON_ID, EMAIL, FIRST_NAME, LAST_NAME
from PERSONS 
where (upper(FIRST_NAME) like upper(:TheName)||'%'
   or  upper(LAST_NAME)  like upper(:TheName)||'%')
  and PERSON_ID between :LowUserId and :HighUserId
order by EMAIL

At runtime, when you set an additional WHERE clause like person_type_code = :ThePersonType as the test program did in Example 5-24, the framework nests the original query into an inline view like the sample shown in Example 5-30.

Example 5-30 Runtime-Generated Query With Inline Nested Query

SELECT * FROM(
select PERSON_ID, EMAIL, FIRST_NAME, LAST_NAME
from PERSONS 
where (upper(FIRST_NAME) like upper(:TheName)||'%'
   or  upper(LAST_NAME)  like upper(:TheName)||'%')
  and PERSON_ID between :LowUserId and :HighUserId
order by EMAIL) QRSLT

Then the framework adds the dynamic WHERE clause predicate at the end, so that the final query the database sees is like the sample shown in Example 5-31.

Example 5-31 Runtime-Generated Query With Dynamic WHERE Clause

SELECT * FROM(
select PERSON_ID, EMAIL, FIRST_NAME, LAST_NAME
from PERSONS 
where (upper(FIRST_NAME) like upper(:TheName)||'%'
   or  upper(LAST_NAME)  like upper(:TheName)||'%')
  and PERSON_ID between :LowUserId and :HighUserId
order by EMAIL) QRSLT
WHERE person_type_code = :ThePersonType

This query "wrapping" is necessary in the general case since the original query could be arbitrarily complex, including SQL UNION, INTERSECT, MINUS, or other operators that combine multiple queries into a single result. In those cases, simply "gluing" the additional runtime WHERE clause onto the end of the query text could produce unexpected results because, for example, it might apply only to the last of several UNION'ed statements. By nesting the original query verbatim into an inline view, the view object guarantees that your additional WHERE clause is correctly used to filter the results of the original query, regardless of how complex it is. The consequence (that results in an ORA-00904 error) is that the dynamically added WHERE clause can refer only to columns that have been selected in the original query.

The simplest solution is to add the dynamic query column names to the end of the query's SELECT list on the Edit Query dialog (click the Edit SQL Query button on the Query page of the overview editor for the view object). Just adding the new column name at the end of the existing SELECT list — of course, preceded by a comma — is enough to prevent the ORA-00904 error: JDeveloper will automatically keep your view object's attribute list synchronized with the query statement. Alternatively, Section 5.9.4.7, "Limitation of Inline View Wrapping at Runtime" explains how to disable this query nesting when you don't require it.

The test client program in Example 5-24 now produces the results shown in Example 5-32.

Example 5-32 Named Bind Variables Resulting From Corrected TestClient

---
116 S. Baida
---
116 S. Baida
---
---
116 S. Baida

5.10.8 What You May Need to Know About Named Bind Variables

There are several things you may need to know about named bind variables, including the runtime errors that are displayed when bind variables have mismatched names and the default value for bind variables.

5.10.8.1 An Error Related to Clearing Bind Variables

You need to ensure that your application handles changing the value of bind variables properly for use with activation and passivation of the view object instance settings at runtime. For example, before you deploy the application, you will want to stress-test your application in JDeveloper by disabling application module pooling, as described in Section 40.10, "Testing to Ensure Your Application Module is Activation-Safe." Following the instructions in that section effectively simulates the way your application will manage the passivation store when you eventually deploy the application.

When the application reactivates the pending state from the passivation store upon subsequent requests during the same user session, the application will attempt to set the values of any dynamically added named WHERE clause bind variables. Changing the values to null before passivation takes place will prevent the bind variable values from matching the last time the view object was executed and the following error will occur during activation:

(oracle.jbo.SQLStmtException) JBO-27122: SQL error during statement preparation.
(java.sql.SQLException) Attempt to set a parameter name that does not occur in SQL: 1

Do not change the value of the bind variables (or other view object instance settings) just after executing the view object. Rather, if you will not be re-executing the view object again during the same block of code (and therefore during the same HTTP request), you should defer changing the bind variable values for the view object instance until the next time you need them to change, just before executing the query. To accomplish this, use the following pattern:

  1. (Request begins and application module is acquired)

  2. Call setWhereClause(null) to clear WHERE clause

  3. Call setWhereClauseParams(null) to clear the WHERE clause bind variables

  4. Call setWhereClause() that references n bind variables

  5. Call setWhereClauseParams() to set the n values for those n bind variables

  6. Call executeQuery()

  7. (Application module is released)

5.10.8.2 Errors Related to Naming Bind Variables

You need to ensure that the list of named bind variables that you reference in your SQL statement matches the list of named bind variables that you've defined in the Bind Variables section of the overview editor's Query page for the view object. Failure to have these two agree correctly can result in one of the following two errors at runtime.

If you use a named bind variable in your SQL statement but have not defined it, you'll receive an error like this:

(oracle.jbo.SQLStmtException) JBO-27122: SQL error during statement preparation.
## Detail 0 ##
(java.sql.SQLException) Missing IN or OUT parameter at index:: 1

On the other hand, if you have defined a named bind variable, but then forgotten to reference it or mistyped its name in the SQL, then you will see an error like this:

oracle.jbo.SQLStmtException: JBO-27122: SQL error during statement preparation.
## Detail 0 ##
java.sql.SQLException: Attempt to set a parameter name that does not occur in the SQL: LowUserId

To resolve either of these errors, double-check that the list of named bind variables in the SQL matches the list of named bind variables in the Bind Variables section of the overview editor's Query page for the view object. Additionally, open the Bind Variables dialog for the bind variable and verify that the Reference checkbox is not still deselected (the default). To use the bind variable in a SQL statement, you must select the Reference checkbox.

5.10.8.3 Default Value of NULL for Bind Variables

If you do not supply a default value for your named bind variable, it defaults to the NULL value at runtime. This means that if you have a WHERE clause like:

PERSON_ID = :ThePersonId

and you do not provide a default value for the ThePersonId bind variable, it will default to having a NULL value and cause the query to return no rows. Where it makes sense for your application, you can leverage SQL functions like NVL(), CASE, DECODE(), or others to handle the situation as you require. For example, the following WHERE clause fragment allows the view object query to match any name if the value of :TheName is null.

upper(FIRST_NAME) like upper(:TheName)||'%'

5.11 Working with Named View Criteria

A view criteria you define lets you specify filter information for the rows of a view object collection. The view criteria object is a row set o