Skip Headers
Oracle® Fusion Applications Developer's Guide
11g Release 4 (11.1.4)

Part Number E15524-09
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
PDF · Mobi · ePub

15 Implementing Search Functions in the UI Shell

This chapter discusses how to implement search functions in the UI Shell page template that is used to build web pages.

This chapter includes the following sections:

For more information about the features, see:

15.1 Implementing Tagging Integration

Tagging is a service that allows users to add tags to selected resources in Oracle WebCenter Portal to contribute to the overall resources other users have visited.

For information about tagging as a component of WebCenter Portal, see the "Integrating the Tags Service" chapter in the Oracle Fusion Middleware Developer's Guide for Oracle WebCenter Portal.

This section assumes that:

Important Considerations

When working with tags, keep these points in mind:

Preliminary Setup

The following steps are condensed from the Oracle Fusion Middleware Developer's Guide for Oracle WebCenter Portal.

  1. Open your current application in JDeveloper.

  2. Ensure that your database connection has access to WebCenter Portal schema. If it does not, create another connection to access WebCenter Portal schema. Name the connection WebCenter. Tagging looks for this connection to access the data.

    Note:

    You should now see at least two connections in your connections.xml file: WebCenter and ApplicationDB.

  3. In the resource Palette, open My Catalog > Web Center Service Catalog > Task Flows. Ensure that you see task flows similar to tagging-launch-dialog.

  4. In the Component Palette, right-click your View Controller project and select Project Properties > Technology Scope > Project Properties. Ensure that Tagging Service is selected. In the Component Palette, search for tagging. You should see Tagging Button and Tagging Menu Item.

  5. Add users and roles, and configure security and authorization for the application; this is highly recommended. Furthermore, it is required for implementing security for tagging.

You now can enable tagging for your business objects.

15.1.1 How to Use the Delivered Oracle WebCenter Portal Tagging Components

Three pieces of information are needed to define tagging to a business object:

  1. You need the unique key of the object that can identify the object. This is stored in a field called RESOURCE_ID (VARCHAR2(200)) in the tagging schema. If you have multiple fields that define the unique key, use a period as the separator. For example, PK1.PK2. Additional restrictions include these:

    • There can be a maximum of only five columns as primary keys, such as PK1.PK2.PK3.PK4.PK5.

    • If any primary key column is null, put "null" in the concatenated Resource Id string. For example, if Resource Id is of type PK1.PK2.PK3, the value can be 123.ABC.null. Do not use just 123.ABC.

    • If your primary key consists of a date, although this is highly unlikely, ensure that the date value that you use in string concatenation is formatted in Oracle Database date format.

    • Developers cannot implement their own resource parser.

  2. SERVICE_ID (VARCHAR2(200)): This is used to identify the object. The Oracle Fusion Applications standard is to use the logical business object name.

  3. NAME (VARCHAR2(200)): This is what will be displayed as the resource that is tagged in the Tag Center, and it will be visible to the end users when they search for a tagged item. Give it a meaningful name, such as <PO Number>+<PO Title> or Invoice Description or Customer Name.

Note:

All fields are varchar2(200). Ensure that you are not violating the constraint. Also note that if, for instance, your product has three business objects that you are planning to tag, then you must build three different services with the proper business object name as the service ID.

15.1.1.1 Tagging a Resource (Business Object)

Follow these steps to tag a resource:

  1. From the Component Palette, select WebCenter Tagging Service. Drag and drop the tagging button onto the page. (If you do not find the button, ensure that you added the WebCenter Tagging JSP Tag Library to your user interface project.)

  2. Open the Property Inspector for the tagging button. Enter the bound values for resourceId, resourceName and serviceId, similar to Example 15-1.

    Example 15-1 Entering Property Information for Tagging Button

    <tag:taggingButton
    resourceId="#{row.AuctionHeaderIdString}"
    resourceName="#{row.AuctionTitle}"
    serviceId="oracle.apps.pon.auctionheadersall"/>
    

    Note:

    Ensure that all the values are of type String.

  3. From the Resource Palette, go to My Catalogs > WebCenter Services Catalog > Task Flows, drag and drop the Tagging Dialog (as a Region). If you do not find the Tagging Dialog, ensure that you added the WebCenter Tagging Service View to your user interface project (Properties > Libraries and classpath). Note that you may drop multiple tagging buttons on your page depending upon your requirement. You need to drop the tagging dialog only once on the page. Whenever you click a tag icon (tagging button) on the page, it will call the same tag dialog region.

    Note:

    If you are placing tags within rows of a table, the Tagging Dialog region must be dropped outside of the table. Otherwise, it is instantiated for every row, which will not work.

    The ability to tag an object is now enabled on the page. The code will look similar to that shown in Example 15-2.

    Example 15-2 Enabling Tagging

    <af:region
    value="#{bindings.tagginglaunchdialog1.regionModel}"
    id="taggi1"/>
    

If you have multiple objects to tag, there will be multiple tagging buttons you will drop on your page, whereas there will be only one tagging dialog.

Tagging is enabled, but to see the tagged resource in the Tag Center, you must create a service definition.

To create a service definition:

  1. Expand Application Resources > Descriptors > ADF Meta-INF. If you already have the service-definition.xml file, open it. Otherwise, create the service-definition.xml file. Important fields are:

    • taskFlowId: The task flow where you want to go.

    • resourceParamList: The list of parameters that you want to pass to the task flow. For example, your task flow takes invoiceId and invoiceType. If the RESOURCE_ID for the tagged item is 123.C45 where 123 is the invoiceId and C45 is the invoiceType, in resourceParamList you should specify invoiceId;invoiceType. The Applications Core class will parse the resource ID 123.C45 and pass invoiceId=123,invoiceType=C45 to the task flow. To use a different delimiter, use the customDelimiter attribute.

    • taskParametersList: The parameters that can be passed to the task flow in addition to the resourceParamList.

    • navTaskKeyList: Do not specify this if it is not used. Otherwise, task flows from Tag Center will always go to a specific tab while the same task flow opened from the Tasklist or API will go to a different tab.

    • navTaskLabel: If using tabbed workareas, this is needed to give a title to the tab that opens showing the tagged object. An Expression Language expression can be used. It will be evaluated when the page loads, so it can be an Expression Language expression that the landing page can resolve.

    • pageResourceParamList: If the RESOURCE_ID for the tagged item is, for example, EastCoast.C45 where EastCoast will be a page level parameter called Region and a task flow parameter called InvoiceType. It is assumed an object will always need both composite keys to be identified as a unique entity. So, the resourceParamList will always contain the same number of parameter names as the composite keys. The task flow must take both EastCoast and C45 as parameters. But the page-level parameters can be called out in the pageParametersList. For example:

      resourceParamList = "Region,InvoiceType"
      pageResourceParamList = "Region"
      
    • pageParametersList: Additional page parameters where the value is static, such as pageParametersList = "Campaign=Sales"

    • customDelimiter: This is optional. The default is a period ".". If you want something different, add this parameter.

      For ease of deployment, service definition files will be stored in Oracle Metadata Service (MDS). Add the service-definition.xml file to the Metadata Archive (MAR) file definition.

      A sample service-definition.xml file is provided in Example 15-3.

      Example 15-3 Sample service-definition.xml

      <service-definition id="FND_DEMO_DOC_TAG" version="11.1.1.0.0"  >
          <resource-view taskFlowId="/WEB-INF/task-flow-1.xml#task-flow-1" >
          <parameters>
              <parameter name="viewId"
                         value="RevenueWorkArea"/>
              <parameter name="webApp"
                         value="ProjectsFinancials"/>
              <parameter name="pageParametersList"
                         value="p1=viewContext"/>
              <parameter name="navTaskKeyList"
                         value="ViewRevenueItem"/>
              <parameter name="taskParametersList"
                        value="a=1;b=2"/>
              <parameter name="resourceParamList"
                          value="invoiceId;invoiceType" />
              <parameter name="navTaskLabel"
                         value="Details"/>
              <parameter name="customDelimiter"
                         value="," />
              <resource-type-key>PAGE_OBJECT_NAME</resource-type-key>
          </parameters>
          </resource-view>
          <name-key>CUSTOM_NA_KEY_TYPE</name-key>
          <description-key>CUSTOM_TY_DESCRIPTION_KEY</description-key>
      </service-definition>
      

      Put the service-definition.xml file in a standard location so there are no conflicts. Create or copy the file, which by default is located at .adf/META_INF/service-definition.xml, to the new standard location. There are two guidelines for where to put the service-definition.xml file:

      • Make it unique so teams of developers are not trying to push files to the exact same location in MDS.

      • Standardize it to be in the meta/oracle/apps/meta directory. The /oracle/apps/meta directory makes the location specific to Oracle applications. The parent meta/ directory is used for MAR selection. The directory structure and contents then resemble:

        meta/ (this directory plus a specific sub-directory structure goes into the MAR)
             oracle/apps/meta/ (namespace unique to MDS)
                  <product-specific-directory-structure>/ (each team has a unique name)
                       service-definition.xml (located in the product directory)
        

        If you use an application-level or project-level service-definition.xml file, you do not need to make any changes as long as your name will be unique to other applications and projects. You should never have two entries for the same SERVICE_ID, whether within the same service-definition.xml file or in separate service-definition.xml files.

        That is, the service-definition.xml file should be under the data model project that contains the entity objects and view objects used for the detail page. If the view object is:

        oracle.apps.scm.receiving.receipts.receiptSummary.protectedUiModel.view.ReceiptSummaryHeaderVO,

        the service-definition.xml location will be:

        oracle.apps.scm.receiving.receipts.receiptSummary.protectedUiModel.meta.oracle.apps.meta.scm.receiving.receipts.receiptSummary.service-definition.xml.

  2. Add the directory, such as meta/oracle/apps/meta/<lba>/<product>/, into the MAR.

    • Open Application > Application Properties > Deployment. Select the MAR file and choose Edit.

    • In the Edit dialog, select User Metadata and choose Add. Browse to select the meta directory you just added and click OK.

    • Select the meta directory (under oracle/apps/) and click OK.

    • Click OK in the Edit MAR dialog.

  3. Add the namespace path /oracle/apps/meta to the adf-config.xml file, as shown in Example 15-4.

    Example 15-4 Adding the Namespace Path to adf-config.xml

    <adf-config
      <adf-mds-config xmlns="http://xmlns.oracle.com/adf/mds/config"
                      version="11.1.1.000">
        <mds-config xmlns="http://xmlns.oracle.com/mds/config" version="11.1.1.000">
           <persistence-config>
              <metadata-namespaces>
                 <namespace path="/oracle/apps/meta"
                  metadata-store-usage="WebCenterFileMetadataStore"/>
              </metadata-namespaces>
              <metadata-store-usage id="WebCenterFileMetadataStore"
                 default-cust-store="true" deploy-target="true">
                 <metadata-store class-name="oracle.mds.dt.persistence.stores.file.SrcControlFileMetadataStore">
                      <property name="metadata-path" value="../../mds"/>
                 </metadata-store>
              </metadata-store-usage>
           </persistence-config>
        </mds-config>
      </adf-mds-config>
    </adf-config>
    
  4. Add the entry shown in Example 15-5 to your adf-config.xml file to enable the default resource action handler from Applications Core.

    Example 15-5 Enabling the Default Resource Action Handler

    <wpsC:adf-service-config>
        <resource-handler class="oracle.apps.fnd.applcore.tags.handler.FndResourceActionViewHandler"/>
    </wpsC:adf-service-config>
    

    Add this instruction in the header:

    xmlns:wpsC="http://xmlns.oracle.com/webcenter/framework/service"

  5. Run the page.

    • The Tag icon will appear on the page. When you click the Tag icon, it will take you to the UI where you can enter a new Tag.

    • You can share the tag or not share it. Only shared tags are available to Oracle Fusion Applications Search.

    • After creating the tag for the first time, again hover the mouse over the icon. It will display My Tags and Popular Tags.

    • Clicking the Tag takes you to the Tag Center UI where you are shown all resources that have been tagged by that word.

    • Clicking a resource from Tag Center will take you to the task flow defined in your service definition, passing the parameters you specified so you can view the object.

15.1.1.2 Enabling Multiple Navigation Targets

Searchable and taggable objects are defined at the view object or logical business object level. The same view object or business object can be viewed and tagged in more than one workarea and task flow. The requirement is that all users must be able to go from Tag Center to a detail task flow for which they have privileges. If this task flow is available in the current workarea, use this target before any other.

This is implemented by supplying multiple navigation targets in the current service-definition.xml file. Each target will have its parameter separated by a caret (^).

Example 15-6 shows how to define a list of three targets:

Example 15-6 Defining a List of Three Targets

<resource-view
    taskFlowId="/WEB-INF/dummy^/WEB-INF/dummy^/WEB-INF/Test1Frag2TF.xml#Test1Frag2TF">
  <parameters>
    <parameter name="viewId" value="DummyView^Region6UIShellPage^Test2"/>
    <parameter name="webApp"
      value="ApplCoreCRMDemo^ApplCoreCRMDemo^SimpleApplication1_application1"/>
    <parameter name="pageParametersList" value=""/>
    <parameter name="taskParametersList" value=""/>
    <parameter name="resourceParamList" value="val"/>
    <parameter name="navTaskLabel" value="My Employee Details^My Employee Details 2^My Employee Details"/>
    <parameter name="applicationStripe"
       value="ApplicationsCommon^ApplicationsCommon^AppStripe1"/>
    <parameter name="pageDefinitionName"
       value="pageDef.not.exist^oracle.apps.view.pageDefs.Region6UIShellPagePageDef^oracle.apps.view.pageDefs.Test1PageDef"/>
   </parameters>
</resource-view>

The lists of taskFlowId, viewId, webApp, and so on, are specified as a delimited string, with each value delimited by a caret. Two parameters, applicationStripe and pageDefinitionName, are available for checking security when the target is in a different webApp.

If the current view ID matches any one of the viewId values in the target list, you take the corresponding task flow (that is, if the third viewId value matches the current view ID, you take the third taskFlowId value) and open it in the current page, if the user has view access to that task flow, which overrides the order of the list. Otherwise, you check a list of link targets for the first target to which the current user has access. You are responsible for making sure that all users who can access this object have at least one match to a target task flow defined in the service-definition.xml file.

When the target is in a different webApp, the security check is performed by calling checkBulkAuthorization API. Therefore, you must use a standalone Oracle WebLogic Server and LDAP policy store. This requirement is optional when the lists of targets are within the same webApp.

15.1.1.3 Tagging a Resource at the Row Level of a Table

To add row-level tagging to a table, add a new empty column to hold the Tag button or link.

All other steps remain the same as described in Section 15.1.1.1, "Tagging a Resource (Business Object).".

15.1.1.4 Searching for a Tag

We recommend that you do not add the Tag Search in your page. The standard way to perform a search is to start the Tag Center UI by clicking the Tag icon, or from Tags in the UI Shell global area and do the search there.

15.1.1.5 Resource Viewer for Tagged Items

It can be handy for a user to be able to click a tag and open a document. To do this, Web Center Tagging needs to know a resource viewer (a task flow) where it should take the user to show the required information.

You can build a task flow where you can take the user for that resource and show the desired additional information as follows:

  1. Select or create a new task flow that will act as your resource viewer for a service (business object):

    1. In the task flow definition, define an input parameter that is called resourceId (in this example), with class equal to java.lang.String, with value equal to #{pageFlowScope.resourceId}, and with required set to enabled.

      Note that the value for resourceId is set automatically when clicking a tagged item link in Tag Center.

    2. Create a method with a parameter of object ID in the application module for a tagged item (named, for instance, setCurrentRow) to set the view object row based on the passed resource ID parameter.

    3. Add the setCurrentRow method as the default activity in the task flow and bind the method (right click the method in the task flow and go to page definition) with the parameter value of #{pageFlowScope.resourceId}, type java.lang.String, and name equal to the parameter variable name in the setCurrentRow method signature.

    4. Add the bounded task flow for the details or information page of the tagged item to the new task flow.

    5. Add a control flow case from the setCurrentRow method to the details or information page task flow, as shown in Figure 15-1.

      Figure 15-1 Adding A Control Flow to Details Task Flow

      Adding Control Flow to Details Task Flow
  2. Register the new task flow in the service-definition.xml file. Register the resource viewer for a particular service (business object) to its section in the service definition file. See Example 15-3 for samples of the service-definition and resource-view entries.

Basically, you have defined a task flow that takes the resource ID as input. Use the resource ID to uniquely identify the business object and display any desired extra detail. Note that clicking a tagged item in Tag Center displays the details or information page for the tagged item in the Local Area of the workarea page for that task flow.

15.1.2 Implementing Tagging Security

By default, tagging does not provide any security. To avoid this problem, implement security for each service (business object) for which tagging is enabled:

  • For a business object, first implement data security.

  • Add the authorizerClass and dataSecurityObjectName parameters to the service-definition.xml file, as shown in Example 15-7.

    Example 15-7 Registering a New Class in service-definition.xml

    <service-definition id="FND_DEMO_DOC_TAG" version="11.1.1.0.0"  >
        <resource-view taskFlowId="/WEB-INF/task-flow-1.xml#task-flow-1" >
         authorizerClass="oracle.apps.fnd.applcore.tags.util.FndTagSecurity"/>
        <parameters>
           <parameter name="dataSecurityObjectName" value="FND_CRM_CASES"/>
           <parameter name="dataSecurityPrivilegeName" value="read"/>
    

    FND_CRM_CASES is the object you want to secure that is found in the FND_OBJECTS table. This is usually the object's main table name.

    If the dataSecurityPrivilegeName parameter is not set, it defaults to read privilege. This attribute is used in cases where a single table has different privileges for different users.

  • Put the service definition into MDS. For ease of deployment, service definition files will be stored in MDS.

15.1.3 How to Use Tagging in a UI Shell Application

The following describes examples of how tagging appears in the UI Shell:

  • Tagging an object by having the Tag button and tagging dialog in the task flow. On clicking the Tag button, a tagging dialog is displayed and prompts the user to tag the object with a name, as shown in Figure 15-2.

    Figure 15-2 Tagging an Object with a Name

    Tagging an Object with a Name
  • To see the tagged object in the Tag Center task flow, click the Tags link in the UI Shell Global Area and the Tag Center task flow displays the list of tags available, as shown in Figure 15-3.

    Figure 15-3 Displaying the List of Available Tags

    Displaying the List of Available Tags
  • Click one of the tags in the tag cloud region of the Tag Center to view the tagged items, as shown in Figure 15-4.

    Figure 15-4 Viewing Tagged Items

    Viewing Tagged Items
  • Click the tagged item to view the object in the task flow mentioned in the service definition file, as shown in Figure 15-5.

    Figure 15-5 View Object Listed In Service Definition File

    View Object from Service Definition File
  • To check whether or not the object is already tagged, hover over the Tag button to see the tags. On clicking the tag link on the hover dialog, the Tag Center task flow will be started with the selected tag, as shown in Figure 15-6.

    Figure 15-6 Starting Flow with Selected Tag

    Launching Flow with Selected Tag

15.2 Implementing Recent Items

Recent Items tracks a list of the last 20 task flows visited by a user. The Recent Items list is persistent across user sessions and a task can be restarted from the Recent Items list. The feature is automatically turned on and will be available automatically in pages using the UI Shell template. Security must be disabled to turn Recent items off.

Before You Begin

For the Recent Items feature to work, you must configure the user session and ADF Security. See Chapter 48, "Implementing Application User Sessions." Without security enabled, recent items will not be captured because the data is recorded for each authenticated user.

15.2.1 How to Choose Labels for Task Flows

Recent Items records the task flow labels for a task flow that has started. Therefore, you must carefully choose the labels for task flows, and must provide task flow labels for all task flows, even if they are meant to be used in no-tab mode (see Section 14.2.3.4, "Supporting No-Tab Work Areas").

15.2.2 How to Call Sub Flows

The openMainTask method is used to open a new task in the Main Area of Oracle Fusion web applications that use UI Shell templates. Besides opening a new tab, openMainTask also pushes a new task flow history object onto a stack, which is used to keep track of all task flows that have been opened. The task flow ID and its associated parameter values are encapsulated in the task flow history object.

Having this information, the call to closeMainTask pops the stack to get the last task flow ID and its parameter values that were displayed, and reinitializes the Main Area with that task flow and parameter information.

When a task flow is called from the Local Area task flow using task flow call activity, it is called a sub flow. By default, sub flows will not be recorded on the stack as described. Two new APIs are exposed in FndUIShellController data control for registering sub flows: openSubTask and closeSubTask.

15.2.2.1 Sub Flow Registration APIs

Use the openSubFlow and closeSubFlow APIs to record sub flows to Recent Items. Whenever an ADF Controller task flow call takes place, no notification is raised to Applications Core or UI Shell. So, unlike starting a task from a tasks list, you need to explicitly notify the UI Shell for sub flow calls.

When the openSubTask API is called before a subflow is started, the sub flow ID and its parameter values are pushed onto the stack. Applications Core also notifies the Recent Items implementation with recorded task flow information. This essentially makes a sub flow able to be bookmarked by Recent Items, and can be started directly from the selection of menu items on Recent Items.

Note that registering sub flows to Recent Items is optional.

Implementation

This API is exposed as the data control methods FndUIShellController.openSubTask and FndUIShellController.closeSubTask that can be dragged and dropped to page fragments to create links to notify the UI Shell. The FndUIShellController data control is automatically available to all Oracle Fusion applications that reference Applications Core libraries.

Example 15-8 shows the signature and Javadoc of the method.

Example 15-8 Recent Items API

/**
* Notify UIS hell to record a given sub flow on the stack and 
* also notify Recent Items to include it on the list.
*
* @param taskFlowId Task flow to open
* @param parametersList Parameters list for the task flow.
*                       This is a semicolon delimited String
*                       of name-value pairs. For example,
*                       "param1=value1;param2=value2".
*
* @param label Label for the task flow.
* @param keyList Key list to locate the task flow instance.
*                This is a semicolon delimited keys or key-value pairs.
*                For example, "key1;key2=value2". If only the key is specified,
*                the value is picked up from parametersList with the same
*                name as the key.
*
* @param taskParametersList Parameters list to pass in to the task flow to open
*                in the target workspace. This is a semicolon delimited String
*                of name value pairs. For example,
*                "param1=value1;param2=value2."
*
* @param methodParameters This can be used for passing
*                Java object into the task flow that is specified 
*                in taskFlowId parameter. Use <code>setCustomObject() API</code>
*                in FndMethodParameters for setting the java object.
*
* @return For internal Contextual Event processing
*/
 
public FndMethodParameters openSubTask(String taskFlowId,
String parametersList,
String label,
String keyList,
String taskParametersList,
String viewId,
String webApp,
FndMethodParameters methodParameters)
 
/**
* Closes the currently-focused sub-task and the focus moves to the 
* task from which this sub-task was started.
*
* @param methodParameters For future implementation. No-op for now.
* @return For internal Contextual Event processing
*/
public FndMethodParameters closeSubTask(FndMethodParameters methodParameters)

All the parameters required to be passed in openSubTask are exactly same as used by the Navigate API. For more information, see Section 16.1, "Introducing the Navigate API."

15.2.2.2 openSubTask API Labels

The openSubTask API accepts the same set of parameters as used by the Navigate API. If no label is specified in the openSubTask API, Recent Items will register it with the name of the parent task flow's label. You should set a different label based on the business use case in the openSubTask API. Failing to do so will register this flow with the same label as the parent task flow's label and, therefore, will make it impossible to distinguish between the parent flow and the sub flow entry in the Recent Items list.

15.2.2.3 Starting from Recent Items

Whatever task flow details are registered while invoking the openSubTask API will be used by Recent Items to start it. Recent Items takes care of starting the task flow in the right work area and web application. You do not need to do anything for that. Because the openSubTask API supports parametersList, you can pass some requirement-specific values to it while registering the task flow to Recent Items. On starting, those passed values are available in the pageFlowScope. You can analyze these values and make decisions, such as if you need to first initialize the parent flow, or if you need to set Visible to False on some of the actions on the page.

15.2.3 How to Enable a Sub Flow to Be Bookmarked in Recent Items

To record sub flows into the Recent Items list, applications need to call the openSubTask API right before sub flows are started. openSubTask takes parameters similar to the Navigate API. One of these is task flow ID. For this, you need to specify the parent flow's ID (or main task's ID). In other words, sub flows need to be executed by using the parent flow, even though they are started from the Recent Items menu.

If your sub flow does not need to be bookmarked by Recent Items, you do not need to change anything. Otherwise, you need to modify your parent flow and sub flow as described in this section. After the changes, sub flows can be started in two ways:

  • From original flows

  • From Recent Items menu items using recorded information

Both will start the execution in the parent flow. Because the sub flow must be piggybacked on the parent flow when it is started from the Recent Items menu, you need to change the parent flow following these directions:

  • Add a new router activity at the beginning of the parent flow. Based on a test condition, it will route the control to either the original parent flow or the task flow call activity (that is, the sub flow).

  • Add an optional method call activity to initialize the sub flow before it is started from the Recent Items menu. Product teams can code the method in such a way that it can navigate to the sub flow after initializing the parent state. This allows product teams to render the contextual area, navigating back to the parent flow from the sub flow, and any other customizations.

  • Bind openSubTask to the command component (such as a link or button) which causes the flow to navigate to the task flow call activity in the original parent flow. The openSubTask API registers the parent flow details and input parameters to the sub flow (to be started as a sub flow later) to the Applications Core task flow history stack.

Usually, you do not need to modify your sub flow for this task. However, you can consolidate the initialization steps from two execution paths in this way:

  • Remove initialization parts from both paths in the parent flow. Instead, set input parameters in both paths only.

  • Modify the sub flow to take input parameters.

  • Add a new method call (such as initsubflow) at the beginning of the sub flow to initialize states in the parent flow (for example, parent table) so that the sub flow can be started in the appropriate context.

Note that the design pattern also requires the application to be able to navigate back to the parent flow from the sub flow. The initialization code should take this into consideration, such as by setting up states to allow the sub flow to navigate back.

In this example, you will use an Employee sample implementation to demonstrate the details of this design pattern.

Sub Flow Sample Application

As shown in Figure 15-7, users select Subflow Design Pattern from the task list. They then specify some criteria to search for a specific employee or employees. From the list, they can choose the employee for whom they want to show the details.

Figure 15-7 Example List of Employees

Example List of Employees

The Ename column in the search result table is a link that can be used to navigate to the employee detail page of a specific employee. When this link is clicked, a sub flow (or nested bounded task flow) is called to display the Employee Complete Detail page, as shown in Figure 15-8.

Figure 15-8 Example Employee Complete Detail Page

Example Employee Complete Detail Page

15.2.3.1 Implementing the Sub Flow Design Pattern

The parent task flow named ToParentSFFlow is shown in Figure 15-9.

Figure 15-9 Example Parent Task Flow

Example Parent Task Flow

The router activity decideFlow decides whether the control task flow should go to the original parent task flow path (initParent) or to the sub task flow path (toChild). The condition is defined as:

<router id="decideFlow">
  <case>
    <expression>#{pageFlowScope.Empno == null}</expression>
    <outcome id="__9">initParent</outcome>
  </case>
 
  <case>
    <expression>#{pageFlowScope.Empno != null}</expression>
    <outcome id="__10">toChild</outcome>
  </case>
 
  <default-outcome>initParent</default-outcome>
</router>

The test checks whether or not the Empno variable in the parent task flow's pageFlowScope is null. #{pageFlowScope.Empno} is set using its input parameter Empno when the parent task flow is called. The input parameters on the parent task flow (that is, ToParentSFFlow) are defined as:

<input-parameter-definition>
  <name>Empno</name>
  <value>#{pageFlowScope.Empno}</value>
  <class>java.lang.String</class>
</input-parameter-definition>

When the parent task flow is started from the task list, the Empno parameter is not set (that is, it is not defined in the application menu's itemNode). Therefore, the parameter is null and the router will route it to the initParent path.

When the sub task flow is recorded through the openSubTask API, the Empno parameter is set on parametersList as:

<methodAction id="openSubTask" RequiresUpdateModel="true"
                 Action="invokeMethod" MethodName="openSubTask"
                 IsViewObjectMethod="false" DataControl="FndUIShellController"
                 InstanceName="FndUIShellController.dataProvider"
                 ReturnName="FndUIShellController.methodResults.openSubTask_FndUIShellController_dataProvider_openSubTask_result">
     <NamedData NDName="taskFlowId" NDType="java.lang.String"
         NDValue="/WEB-INF/oracle/apps/xteam/demo/ui/flow/ToParentSFContainerFlow.xml#ToParentSFContainerFlow"/>
     <NamedData NDName="parametersList" NDType="java.lang.String"
                NDValue="Empno=#{row.Empno}"/>
     <NamedData NDName="label" NDType="java.lang.String"
                NDValue="#{row.Ename} complete details"/>
     <NamedData NDName="keyList" NDType="java.lang.String"/>
     <NamedData NDName="taskParametersList" NDType="java.lang.String"/>
     <NamedData NDName="viewId" NDType="java.lang.String"
                NDValue="/DemoWorkArea"/>
     <NamedData NDName="webApp" NDType="java.lang.String"
                NDValue="DemoAppSource"/>
     <NamedData NDName="methodParameters"
         NDType="oracle.apps.fnd.applcore.patterns.uishell.ui.bean.FndMethodParameters"/>
</methodAction>

You also set up:

  • taskFlowId to be the parent task flow's, not the sub task flow's

  • label to be the sub task flow's

When users click the link (the Ename) to which the openSubTask method is bound, openSubTask will be called. This link component is defined as:

<af:column sortProperty="Ename" sortable="false"
           headerText="#{bindings.ComplexSFEmpVO.hints.Ename.label}"
           id="resId1c2">
  <af:commandLink id="ot3" text="#{row.Ename}"
                  actionListener="#{bindings.openSubTask.execute}"
                  disabled="#{!bindings.openSubTask.enabled}"
                  action="toChild">
    <af:setActionListener from="#{row.Empno}"
                          to="#{pageFlowScope.Empno}"/>
  </af:commandLink>
</af:column>

Note that when the link is clicked:

  • actionListener and the action specified on the link are executed, in that order.

  • openSubTask is called only from the original parent task flow path (that is, initParent), not from the sub task flow path (that is, toChild).

The EmployeeDetails activity in Figure 15-9 is a Task Flow Call activity that invokes the ToChildSFFlow sub task flow. Before the sub task flow is executed, add initialization steps. These initialization steps could include, but are not limited to:

  • Set up parent states. For this example, set the selected employee's row to be the current row.

  • Set up the Contextual Area state.

  • Set up states to allow the sub task flow to navigate back to the parent task flow.

There are two approaches to setting up the initialization steps:

  • In the parent task flow

  • In the sub task flow

For the first approach, you can add logic to initialize both paths before the task flow call activity in the parent task flow. For the second approach, you initialize states in the sub task flow by using input parameters of the sub task flow. For example, the sub task flow will take an input parameter named Empno. In effect, the second approach just postpones the initialization to the sub task flow.

The definition of input parameters in the task flow call activity is:

<task-flow-call id="EmployeeDetails">
     <task-flow-reference>
       <document>/WEB-INF/oracle/apps/xteam/demo/ui/flow/ToChildSFFlow.xml</document>
       <id>ToChildSFFlow</id>
     </task-flow-reference>
     <input-parameter>
       <name>Empno</name>
       <value>#{pageFlowScope.Empno}</value>
     </input-parameter>
</task-flow-call>

Note that this means that the calling task flow needs to store the value of Empno in #{pageFlowScope.Empno}. For example, from the original parent task flow path, it is set to be #{row.Empno} using the setActionListener tag. For the sub task flow path, it is set using the parent task flow's input parameter Empno. On the sub task flow, you need to specify its input parameters as:

<task-flow-definition id="ToChildSFFlow">
   <default-activity>TochildSFPF</default-activity>
   <input-parameter-definition>
     <name>Empno</name>
     <value>#{pageFlowScope.Empno}</value>
     <class>java.lang.String</class>
   </input-parameter-definition>
   ...
</task-flow-definition>

Note that the name of the input parameter (Empno) must be the same as the parameter name defined on the task flow call activity. When the parameter is available, Oracle ADF will place it in #{pageFlowScope.Empno} to be used within the sub task flow. However, this pageFlowScope is different from the one defined in the task flow call activity because they have a different owning task flow (that is, parent task flow versus sub task flow).

The definition of the sub task flow is shown in Figure 15-10:

Figure 15-10 Example Sub Task Flow Definition

Example Sub-flow Definition

In the sample implementation, you implemented the initialization step in the sub task flow. The Empno variable is passed as a parameter to the sub task flow and used to initialize the parent state. When the sub task flow is started, the default view activity (TochildSFPF) is displayed. Before it renders, the initPage method on the ChildSFBean will be executed. The page definition of the default page is defined as:

<pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel">
 <parameters/>
 <executables>
   ...
   <invokeAction id="initPageId" Binds="initPage" Refresh="always"/>
 </executables>
 <bindings>
   ...
   <methodAction id="initPage" InstanceName="ChildSFBean.dataProvider"
                 DataControl="ChildSFBean" RequiresUpdateModel="true"
                 Action="invokeMethod" MethodName="initPage"
                 IsViewObjectMethod="false"
                 ReturnName="ChildSFBean.methodResults.initPage_ChildSFBean_dataProvider_initPage_result"/>
    ...
 </bindings>
</pageDefinition>

The initPage method is specified in the executables tag and will be invoked when the page is refreshed. The initPage method itself is defined as:

public void initPage()
{ 
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExpressionFactory exp = facesContext.getApplication().getExpressionFactory();
    DCBindingContainer bindingContainer =
      (DCBindingContainer)exp.createValueExpression(
          facesContext.getELContext(),"#{bindings}",DCBindingContainer.class).getValue(facesContext.getELContext());
    ApplicationModule am = bindingContainer.getDataControl().getApplicationModule();
 
    ViewObject vo = am.findViewObject("ComplexSFEmpVO");
    vo.executeQuery();
 
    Map map = AdfFacesContext.getCurrentInstance().getPageFlowScope();
    if(map !=null){
         Object empObj = map.get("Empno");
         if(empObj instanceof Integer){
             Integer empno =(Integer)map.get("Empno");// new Integer(empnoStr);
             Object[] obj = {empno};
             Key key = new Key(obj);
             Row row = vo.getRow(key);
             vo.setCurrentRow(row);
         }
         else
         {
             String empnoStr = (String)map.get("Empno");
             Integer empno = new Integer(empnoStr);
             Object[] obj = {empno};
             Key key = new Key(obj);
             Row row = vo.getRow(key);
             vo.setCurrentRow(row);
         }
     }
}

The initPage method takes the input parameter Empno from #{pageFlowScope.Empno} as a key to select a row and set it to be the current row in the master Employee table.

15.2.4 How to Use Additional Capabilities of the Recent Items openSubTask API

The openSubTask API has additional capabilities. For example, consider an employee search page in which you enter parameters such as department number and manager ID, and search for the matching employee records. You can use the openSubTask API to register a search page with search parameters. The next time the user can see the search results by just starting it from the Recent Items menu. This is similar to using parametersList to specify search parameters while registering the search task flow. While starting, additional programming can be done to retrieve the search parameters and execute the query with the parameter values.

Favorites

As soon as tasks are recorded on the Recent Items list, they are eligible for Favorites. The Favorites menu is implemented on top of Recent Items. Any current task on the Recent Items list can be bookmarked and placed in the Favorites folders. Currently, only a one-level folder is supported. Similar to Recent Items, tasks on the Favorites list can be started directly from the list. So, the description in this section for Recent Items applies also to the Favorites implementation. For example, sub flows based on the design pattern described in this section can be registered on the Favorites list as well as the Recent Items list.

15.2.5 How to Implement Data Security for Recent Items and Favorites

Data security controls access to the data displayed on the target. When data security is enforced on the target page, any changes to the access that the user has is properly reflected on the data.

However, there are use cases in Oracle Fusion Applications where the Recent Items and Favorites features may cause security issues. In some cases there is a master/detail relationship between objects in which only the parent object has data security implemented. The child object has no data security enforced and is expected to inherit security from the parent. In such cases, the user can only navigate to the child task flow through the parent task flow. But because the child task flow can be added as a Recent Item or Favorite, users can navigate directly to the child through Recent Items, whether or not they still have access to the parent.

Data security ensures that user access is properly enforced on all flows that can be accessed from Recent Items or Favorites.

Implementation

Implementation consists of ensuring that security is enforced consistently in all scenarios and that authorization exceptions are handled by the standard central method.

Security Enforcement

For function security, no additional implementation is required. The recommendations for data security are:

  • Data security should be applied on an appropriate level. For example, in a master/detail relationship, security definitions should be created on both parent and child objects and applied on a proper level.

  • If the child record inherits the security from its parent, then the parent's security must be programmatically enforced on a sub flow. This should be done by adding a default method activity on the task flow and calling the data security API to check that the user has access to the parent. If the user does not have proper access, an authorization exception is generated.

    In addition, you should programmatically enforce the parent data security where applicable. For instance, if a view object takes the parent primary key as a parameter, before executing the query the code should check that the user has access to the parent.

15.2.6 Known Issues

  • Recent Items are persistent across user sessions.

  • You may see a null pointer exception when all the task flow parameters are not supplied values.

15.3 Implementing the Watchlist

The Watchlist is a portlet or menu, accessible to Oracle Fusion Applications users, that provides a summary of items that a user wants to track. The Watchlist includes seeded items (items that are provided out of the box) categorized by functional areas, and items created by the user. Technically, the Watchlist presents a list of pre-queried searches (saved searches or standard queries) of things the user wants to track. Each item is composed of descriptive text followed by a count. Each item also is linked to a page in a work area where the individual items of interest are listed.

The Watchlist is available both as a dashboard region in the Welcome tab of the Home dashboard, and as a global menu. These are two views of the same content. The dashboard region is available to users as soon as they log in, while the global menu is accessible as they navigate through the suite.

The Watchlist will be refreshed to fetch new counts and items whenever the user navigates to the Home page. The Watchlist can refresh the entire list or individual categories as needed. Users can personalize the Watchlist to hide or show items.

Figure 15-11 shows an example of the Watchlist portlet and menu.

Figure 15-11 Example Watchlist Portlet and Menu

Example Watchlist Portlet and Menu

You have these high-level tasks:

15.3.1 Watchlist Data Model Effects

Product teams will seed data into the ATK_WATCHLIST_CATEGORIES and ATK_WATCHLIST_SETUP tables. Rows in the ATK_WATCHLIST_ITEMS will be managed by Watchlist code, but you will query it for testing verification.

The only other data model effect will be in the creation of summary tables. These summary tables help with retrieving the count of Watchlist items with data security. See Section 15.3.4.3.1, "Summary Tables."

15.3.2 Watchlist Physical Data Model Entities

The Watchlist data model is supported by ATK. The tables are:

Table 15-1 ATK_WATCHLIST_CATEGORIES

Column Name Datatype Required Comments

WATCHLIST_CATEGORY_CODE

VARCHAR2(100)

Yes

Primary Key - Unique code based on Product Code Prefix. Ensure that this code begins with <PRODUCT SHORT CODE>_, so that it does not overlap with others.

CATEGORY_LOOKUP_TYPE

VARCHAR2(30)

Yes

Reference to FND_STANDARD_LOOKUP_TYPES.LOOKUP_TYPE

Product teams will seed the lookup type with meaning for the category (VIEW_APPLICATION_ID = 0 and SET_ID = 0). The translated lookup type meaning is shown in the Watchlist UI for the category.

OWNING_MODULE_NAME

VARCHAR2(4000)

Yes

Reference to FND_APPL_TAXONOMY.MODULE_NAME for the owning product or module. This is used for seed data purposes.

OWNING_MODULE_ID

VARCHAR2(32)

Yes

Reference to FND_APPL_TAXONOMY.MODULE_ID for the owning product or module. This is used for seed data purposes.

OWNING_APPLICATION_ID

NUMBER

Yes

Reference to FND_APPL_TAXONOMY.ALTERNATIVE_ID for the owning product or module. This is used for seed data purposes.

REFRESH_SERVICE_ENDPOINT_KEY

VARCHAR2(60)

Yes

The key to determine the host, port, context root, and so on to construct the URL for the service end point (wsdl location).

This will be based on the Applications Core lookup API that will be used to determine the end point.

REFRESH_SERVICE_NAME

VARCHAR2(400)

Yes

The service that must be invoked for count calculation (for refreshing this category).

REFRESH_SERVICE_METHOD_NAME

VARCHAR2(400)

Yes

Obsolete. The hard-coded method name will be refreshWatchlistCategory. Product teams will create this hard-coded service method.

ENABLED

VARCHAR2(1)

Yes

Defaults to Y. Defines if this Watchlist category is enabled or active.

CREATED_BY

VARCHAR2(64)

Yes

Standard WHO Column

CREATION_DATE

TIMESTAMP

Yes

Standard WHO Column

LAST_UPDATED_BY

VARCHAR2(64)

Yes

Standard WHO Column

LAST_UPDATE_DATE

TIMESTAMP

Yes

Standard WHO Column

LAST_UPDATE_LOGIN

VARCHAR2(32)

Yes

Standard WHO Column


Table 15-2 ATK_WATCHLIST_SETUP

Column Name Datatype Required Comments

WATCHLIST_ITEM_CODE

VARCHAR2(100)

Yes

Primary Key - Uses the Category Code Prefix

ITEM_LOOKUP_CODE

VARCHAR2(30)

Yes if WATCHLIST_ITEM_TYPE != USER_SAVED_SEARCH

Reference to FND_LOOKUPS.LOOKUP_CODE

Product teams will seed the lookup code with the meaning for the parent category lookup type. The translated lookup meaning is shown in the Watchlist UI with the count appended.

CATEGORY_CODE

VARCHAR2(30)

Yes

None

PRIVILEGE_BASED

VARCHAR2(1)

Yes

Identification of a Watchlist item that is created against a security action instead of a specific user.

OWNING_PRIVILEGE_NAME

 

Yes if

PRIVILEGE_BASED = Y

Defines if this item is created against a security action. Users that have this action will be able to view this item.

FUNCTION_PRIVILEGE_NAME

VARCHAR2(400)

 

Defines the region action for this item's drilldown work area. This is the page definition for the drilldown view or jspx that is part of your jazn-data.xml file. The user needs this permission policy to view the item in the Watchlist UI.

WATCHLIST_ITEM_TYPE

VARCHAR2(30)

Yes

Defines the Watchlist item type and maps to the lookup. Valid values are:

SEEDED_QUERY (Seeded Query)

SEEDED_SAVED_SEARCH (Seeded Saved Search)

USER_SAVED_SEARCH (User-created Saved Search)

HUMAN_TASK (Worklist item)

HUMAN_TASK_DEF_ID

VARCHAR2(200)

Yes if WATCHLIST_ITEM_TYPE = HUMAN_TASK

Human Task Definition Identifier

HUMAN_TASK_STATE

VARCHAR2(100)

Yes if WATCHLIST_ITEM_TYPE = HUMAN_TASK

Human Task State Identifier.

REFRESH_AGE

NUMBER(9)

Yes if WATCHLIST_ITEM_TYPE != HUMAN_TASK

Defines the time for a count in seconds. After this many seconds have passed since the last refresh time, the Watchlist UI will issue a count recalculation request

VIEW_OBJECT

VARCHAR2(400)

Yes if WATCHLIST_ITEM_TYPE != HUMAN_TASK

Complete path of the view object that must be executed for count calculation.

SUMMARY_VIEW_ATTRIBUTE

VARCHAR2(400)

Yes if WATCHLIST_ITEM_TYPE != HUMAN_TASK and this is a summary view object

Indicates the view object attribute name if using a summary view object for Watchlist count calculation. On execution, this view object returns only one row with the Watchlist item count.

APPLICATION_MODULE

VARCHAR2(400)

Yes if WATCHLIST_ITEM_TYPE != HUMAN_TASK

Complete path of the application module that contains the view object instance that must be executed for count calculation.

AM_CONFIG_NAME

VARCHAR2(400)

Yes if WATCHLIST_ITEM_TYPE != HUMAN_TASK

The application module configuration name for creating an instance of the application module from code. This is typically AMLOCAL.

VIEW_OBJECT_INSTANCE

VARCHAR2(400)

Yes if WATCHLIST_ITEM_TYPE != HUMAN_TASK

The instance name for the view object in the application module.

VIEW_CRITERIA_ID

VARCHAR2(400)

Yes if WATCHLIST_ITEM_TYPE = SEEDED_SAVED_SEARCH

The view criteria that must be applied when executing the view object.

NAVIGATION_URL_KEY

VARCHAR2(60)

Yes

The key to determine the host, port, and context root to construct the URL for the UI drilldown for a Watchlist item.

This will be based on the Applications Core lookup API that is used for UI navigation across Java EE applications.

VIEW_ID

VARCHAR2(400)

Yes

The view ID (as per the UI Shell menu) for the workarea or page that contains the task flow for this Watchlist item's drilldown from the Watchlist UI.

PAGE_PARAM_LIST_STRING

VARCHAR2(400)

No

Parameters list for the page. If the target workarea page accepts page parameters, this is a semicolon-delimited string of name-value pairs.

TASKFLOW_ID

VARCHAR2(400)

Yes

The task flow for this Watchlist item's drilldown from the Watchlist UI.

TF_KEY_LIST_STRING

VARCHAR2(400)

No

Key list to pass into the task flow to open in the target workspace. This is a semicolon-delimited list of keys or key-value pairs. For example, "key1;key2=value2"

TF_PARAMETER_STRING

VARCHAR2(400)

Yes if WATCHLIST_ITEM_TYPE IN (SEEDED_SAVED_SEARCH, USER_SAVED_SEARCH)

Parameters list to pass in to the task flow to open in the target workspace. This is a semicolon-delimited string of name-value pairs. For example, "param1=value1;param2=value2"

For a user-created saved search, the view criteria ID will be appended to this string (the string must end with <paramName>= for saved search).

TASK_TAB_LABEL

VARCHAR2(400)

Yes

Label for the task flow to open in the target workspace.

ENABLED

VARCHAR2(1)

Yes

Defaults to Y. A definition that indicates if this Watchlist category is enabled or active.

CREATED_BY

VARCHAR2(64)

Yes

Standard WHO Column

CREATION_DATE

TIMESTAMP

Yes

Standard WHO Column

LAST_UPDATED_BY

VARCHAR2(64)

Yes

Standard WHO Column

LAST_UPDATE_DATE

TIMESTAMP

Yes

Standard WHO Column

LAST_UPDATE_LOGIN

VARCHAR2(32)

Yes

Standard WHO Column


15.3.3 Supported Watchlist Items

Supported Watchlist items are all asynchronous (that is, queries are executed on demand when the user requests a refresh or just before the Watchlist UI is shown). There are four types of asynchronous Watchlist items (watchlist_item_type):

  • Seeded queries (SEEDED_QUERY)

  • Seeded saved searches (SEEDED_SAVED_SEARCH)

  • User-created saved searches (USER_SAVED_SEARCH)

  • Human task-flow items (HUMAN_TASK)

15.3.3.1 Asynchronous Items Overview: Expense Reports Saved Search

For asynchronous Watchlist items, the count is updated only upon request. For example, in Expenses, there is an expense reports search panel from which users can make searches and save them in MDS for future use. Users should be able to promote their saved searches to the Watchlist for tracking. This Watchlist item (of type USER_SAVED_SEARCH) is asynchronous in that the Watchlist count will be updated only upon request, and events that change the count will not be updating the Watchlist simultaneously. In this case, Watchlist code is responsible for querying the count of an asynchronous Watchlist item on demand.

For the Expense report saved search panel example:

  • Because this item is of type USER_SAVED_SEARCH, Watchlist items are created when the user promotes a saved search on the search panel in Expenses. This invokes a Watchlist service on the Watchlist that does the Watchlist item creation. This is not needed for Watchlist items of type SEEDED_QUERY or SEEDED_SAVED_SEARCH.

  • A request to refresh the Watchlist item count comes from the Watchlist portlet. This will invoke an exposed service, which delegates the call to a method on a provided Watchlist JAR file.

  • The method on the Watchlist JAR file will take care of rerunning the query (on the expenses database) and taking the results to update the Watchlist item count (on the Watchlist database).

15.3.3.2 Summary of Implementation Tasks

At a high level, for asynchronous Watchlist items, your development tasks are:

  • Determine or set up view objects to execute the query for Watchlist count. You may want to include view criteria with bind variables and specify default values for bind variables. (Not needed for Human Task)

    For example, most view objects seeded for the Watchlist would filter by user to show counts specific to the logged-in user. You could create a view criteria with a bind variable called userId and specify the default value as a groovy expression to determine the current user ID from the security context. You then would seed this view criteria ID in the setup table along with the view object. The Watchlist API would execute the view object by applying this view criteria to get the row count. Example 15-9 shows code from the view object xml for a bind variable with a default value.

    Example 15-9 Example Code from the View Object XML for Bind Variable with Default Value

    <Variable
                Name="userId"
                Kind="where"
                Type="java.lang.String">
                <TransientExpression><![CDATA[return adf.context.securityContext.userName;]]></TransientExpression>
              </Variable>
    
  • (Optional) Set up a summary view object to facilitate a refresh count and specify the summary attribute in the Watchlist setup table. Watchlist code would use this information to query the count instead of doing a rowcount on the executed view object results.

  • Include Watchlist model JAR files in your service project and set up a refreshWatchlistCategory service method. This method only will contain code to delegate the call to the nested Watchlist application module method that actually executes the view object queries by reading your Watchlist setup data. This requires that all the corresponding model projects are included as JAR files in this service project so view objects are available in the class path. This service should be exposed so that the Watchlist UI can use it to start the refresh process.

  • Determine and code task flows for drilldown from the Watchlist UI. There is no special coding required for these task flows; the key-value parameter string that you specify in the setup table will be used as the input parameter list when invoking the specified task flow for the UI drilldown on Watchlist items.

  • (Optional) Enable saved search promotion to the Watchlist. Include Watchlist model JAR files in the corresponding project for the query panel and work with the Watchlist API. For promotion and demotion of user-saved searches, code must invoke a method in the provided Watchlist JAR, which then will handle interaction back to the Watchlist. Add promotion and demotion components on the search panel so that saved searches can be used as Watchlist items.

  • Include Watchlist UI and Protected model JAR files in your UI SuperWeb project, to enable Watchlist menu drilldown in the UI Shell Global Area, as shown in Figure 15-12.

    Figure 15-12 Example Watchlist Menu Drilldown

    Example Watchlist Menu Drilldown
  • Create FND_LOOKUPS for the displayed Watchlist category and item meaning (FND_STANDARD_LOOKUP_TYPES.LOOKUP_TYPE). Product teams must seed the lookup type with the meaning for the category (VIEW_APPLICATION_ID = 0 and SET_ID = 0). The translated lookup type meaning is shown in the Watchlist UI for the category, while the corresponding lookup value meanings are shown in the Watchlist UI for items (user saved search item meanings come from the saved search directly). Product teams must create seed data for this lookup.

  • Example 15-10 presents sample code to create or update the lookup.

    Example 15-10 Sample Code to Create or Update Watchlist Lookup

    declare
    begin
    FND_LOOKUP_TYPES_PKG.CREATE_OR_UPDATE_ROW (
      X_VIEW_APPSNAME => 'FND',
      X_LOOKUP_TYPE => 'FIN_EXM_WATCHLIST_CATEGORY',
      X_APPLICATION_SHORT_NAME => 'EXM',
      X_MEANING => 'Expenses',
      X_DESCRIPTION => 'Expenses Watchlist Category',
      X_REFERENCE_GROUP_NAME => null
    );
    end;
     
    declare
    begin
    FND_LOOKUP_VALUES_PKG.CREATE_OR_UPDATE_ROW (
      X_LOOKUP_TYPE           => 'FIN_EXM_WATCHLIST_CATEGORY',
      X_VIEW_APPSNAME         => 'FND',
      X_LOOKUP_CODE           => 'SAVED_EXPENSE_REPORTS',
      X_MEANING               => 'In Progress Expense Reports'
    --  X_SET_CODE              IN VARCHAR2 DEFAULT NULL,
    --  X_DESCRIPTION           IN VARCHAR2 DEFAULT NULL,
    --  X_ENABLED_FLAG          IN VARCHAR2 DEFAULT 'Y',
    --  X_START_DATE_ACTIVE     IN VARCHAR2 DEFAULT NULL,
    --  X_END_DATE_ACTIVE       IN VARCHAR2 DEFAULT NULL,
    --  X_DISPLAY_SEQUENCE      IN NUMBER DEFAULT NULL
      );
    end;
    

Seed Watchlist categories and setup information. Create your category in ATK_WATCHLIST_CATEGORIES and then seed your items in the reference data table (ATK_WATCHLIST_SETUP). The watchlist_item_type determines how the Watchlist code will handle the item.

Note:

HUMAN_TASK items only require seeding in the tables to work; there are no view objects to create.

15.3.4 How to Use the Watchlist

Follow the procedures described in this section to use the Watchlist.

15.3.4.1 Making the Watchlist Link in the UI Shell Global Area Work

To ensure the Watchlist link works in your pages, complete these steps.

  • Add this ADF Library JAR file to the SuperWeb user interface project for your application (the JAR file must be part of your Web Archive (WAR) in the WEB-INF/lib directory):

    fusionapps/jlib/AdfAtkWatchListPublicUi.jar

  • Add this dependent model ADF Library JAR file in your application (the JAR file must be part of your Enterprise Archive (EAR) in the APP-INF/lib directory):

    fusionapps/jlib/AdfAtkWatchListProtectedModel.jar

  • Add this dependent resource bundle ADF Library JAR file in your application (the JAR file must be part of your EAR in the APP-INF/lib directory):

    fusionapps/jlib/AdfAtkWatchListPublicResource.jar

  • Add these resource-ref entries to the web.xml file in your SuperWeb user interface project:

    <resource-ref>
        <res-ref-name>wm/WorkManager</res-ref-name>
        <res-type>commonj.work.WorkManager</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>
    <resource-ref>
        <res-ref-name>jdbc/ApplicationDBDS</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>
    

15.3.4.2 Seed Reference Data (All items)

See Section 15.3.2, "Watchlist Physical Data Model Entities" for details of the entire Watchlist data model. Seed only ATK_WATCHLIST_CATEGORIES and ATK_WATCHLIST_SETUP.

15.3.4.3 Create a Summary View Object (SEEDED_QUERY)

  • By default, Watchlist code will access the application module or view object that is specified in the setup table, and rerun the query to refresh the Watchlist count. The summary view object is one way to get the count. Usually this will be for efficiency reasons.

  • The product team can signal that it wants the Watchlist code to use its summary view object by seeding something in SUMMARY_VIEW_ATTRIBUTE of ATK_WATCHLIST_SETUP. If this is not null, the Watchlist code will get the view object, but instead of running the query, it will take only the first row and get the specified attribute.

  • Your task is to create a view object with the correct count in the attribute specified in the setup table.

15.3.4.3.1 Summary Tables

One common reason to use a summary view object is if the seeded query is based on Multiple-Organization Access Control (MOAC) data security. This is because you can calculate the count of this query for each Business Unit ID (BUID). The count of a user is just the sum of the counts of the BUIDs that the user can access.

For example, say you have a table (or query) that has three rows of BUID #1, three rows of BUID #2, and three rows of BUID #3. The current user has access to BUIDs #1 and #2.

If you wanted to get the count, MOAC would filter the rows by BUID and return six rows.

However, because you are interested only in the count, a more efficient way would be to create a summary table for this table. The summary table keeps track of the count for each BUID. For the example table, the summary table would resemble Table 15-3.

Table 15-3 Example Summary Table

BUID Count

1

3

2

3

3

3


Now, instead of using MOAC to find a count for a particular user, you use MOAC to find the sum of counts for the user. The example user would get the first two rows returned, and you can calculate the total count by summing the count column.

You can use summary tables to populate the summary view object attribute.

15.3.4.4 Create Seeded Saved Searches in MDS (SEEDED_SAVED_SEARCH)

In addition to seeding seeded saved searches in the reference tables, the saved searches need to be seeded in MDS so that when the user visits the saved search panel, the saved search will show as one of the choices in the drop-down box. Saved searches in MDS are stored in the file system as an XML file for each view object. The steps to create this file are:

  • Ensure you have enabled MDS for your application.

  • Run the application and visit the desired search page.

  • Use the UI to create saved searches and name them. For each saved search, select Run Automatically.

  • Examine the adf-config.xml file to determine where your file-based MDS repository is located.

  • In a terminal, change to the directory:

    <MDS repository>/persdef/oracle/apps/.../mdssys/cust/user/<user>/

    The <user> directory would be the user you used to save the search with, or anonymous by default.

  • Inside that directory, there should be an xxxVO.xml.xml file that contains the created saved searches. Keep that file.

  • In that XML file, note the saved search ID, which should match the View Criteria ID in the reference data.

    Note:

    This ID can be different than the display name that you entered in the saved search UI.

15.3.4.5 Creating Application Module and View Objects (All except HUMAN_TASK)

Refer to Section 15.3, "Implementing the Watchlist."

15.3.4.6 Setting Up Service (All except HUMAN_TASK)

For the same Watchlist items, the Watchlist portlet must be able to invoke a refresh. You will set up and expose a service that includes local JAR files for this purpose. The nested Watchlist JAR file can use those local JAR files in its refresh code.

The service will expose the refreshCategory method that will delegate the call to the same method in the nested Watchlist application module. This method will be provided in the Watchlist JAR file and will contain code to perform the category-wide refresh.

15.3.4.7 Importing All Watchlist-Related Application Modules

Your Service project must import the other JAR files from your product that must be used by the Watchlist code.

15.3.4.8 Nesting Watchlist Application Modules

Include AdfAtkWatchListProtectedModel.jar and AdfAtkWatchListPublicModel.jar in your service project, and nest AdfAtkWatchListPublicUi.jar in your service application module.

Set up the AppMasterDB connection that comes with it. Point it to the database where you have seeded your data in the Watchlist tables. This usually is your development database that is used for the ApplicationDB connection.

15.3.4.9 Using the refreshWatchlistCategory Method

This method, shown in Example 15-11, refreshes all Watchlist items in the corresponding category.

Example 15-11 Refreshing Watchlist Items

public void refreshWatchlistCategory(String categoryCode) {
    AtkWatchlistPublicAMImpl wlAM = this.getAtkWatchlistPublicAMImpl();
    wlAM.refreshWatchlistCategory(categoryCode);
}

15.3.4.10 Importing Watchlist JAR Files into the Saved Search Project (USER_SAVED_SEARCH)

For subsequent steps that require running Watchlist APIs from your code, you must import the Watchlist JAR files. These also contain an AppMasterDB connection that must point to the Watchlist database.

  • Add AdfAtkWatchlistProtectedModel.jar and AdfAtkWatchlistPublicService.jar (fusionapps > jlib) as ADF libraries in the appropriate data model projects, preferably in a model project that is visible to both service and user interface model project application modules.

  • Add AdfAtkWatchlistPublicUi.jar as an ADF library to your user interface project.

  • Configure the AppMasterDB connection.

15.3.4.11 Promoting Saved Search to the ATK Watchlist (USER_SAVED_SEARCH)

Every Watchlist-enabled saved search panel must include a component to let the user control which of the saved searches to promote. The pre-seeded saved searches will be shown as static, while the user can use checkboxes to determine which saved searches should be promoted. There will be listeners to this component that will publish business events to make the appropriate worklist changes.

Before You Begin

Ensure that the following steps have been performed.

  • Populate ATK tables with SEED watchlist category information. Product teams need to provide information about the service that refreshes the watchlist item count.

  • Populate ATK tables with appropriate watchlist setup information. There must be a watchlist setup item of type USER_SAVED_SEARCH.

  • Ensure the application is MDS enabled so users can save their searches and that the saved searches exist across sessions.

  • From the watchlist UI, users can drilldown to the transactional UI flows. Ensure that the transactional UI flow is properly set up so that it can show the search page when the user clicks the Watchlist item in the Watchlist UI.

  • In the application project, create a backing bean and register it as a backingBeanScope bean. In the backing bean, create the Java method shown in Example 15-12:

    Example 15-12 Creating the Backing Bean

    import oracle.adf.view.rich.model.QueryDescriptor;
    import oracle.adf.view.rich.model.QueryModel;
    ..................
     
        public List<String> getWatchListUserSavedSearchList() {
            if (AppsLogger.isEnabled(AppsLogger.FINEST)) {
              AppsLogger.write(this, "Watchlist saved search promotion: Entering method getWatchListUserSavedSearchList", AppsLogger.FINEST);
            }
            List<String> WatchListUserSavedSearchList = new ArrayList<String>();
            QueryModel queryModel =
                (QueryModel)evaluateEL("#{bindings.ImplicitViewCriteriaQuery.queryModel}");//See next code sample for evaluateEL()
            if (queryModel != null) {
              if (AppsLogger.isEnabled(AppsLogger.FINEST)) {
                AppsLogger.write(this, "Watchlist saved search promotion: getWatchListUserSavedSearchList method: queryModel is not null", AppsLogger.FINEST);
              }
                List userQueries = queryModel.getUserQueries();
                if (userQueries != null & userQueries.size() > 0) {
                  if (AppsLogger.isEnabled(AppsLogger.FINEST)) {
                    AppsLogger.write(this, "Watchlist saved search promotion: getWatchListUserSavedSearchList method: User Saved Searches exist", AppsLogger.FINEST);
                  }
                    for (int i = 0; i < userQueries.size(); i++) {
                        QueryDescriptor qd = (QueryDescriptor)userQueries.get(i);
                        if(qd != null){
                          if (AppsLogger.isEnabled(AppsLogger.FINEST)) {
                            AppsLogger.write(this, "Watchlist saved search promotion: getWatchListUserSavedSearchList method: Adding user saved search name to the watchListUserSavedSearchList using QueryDescriptor getName: " + qd.getName(), AppsLogger.FINEST);
                          }
                          WatchListUserSavedSearchList.add(qd.getName());
                        }
                    }
                }
            }
            if (AppsLogger.isEnabled(AppsLogger.FINEST)) {
              AppsLogger.write(this, "Watchlist saved search promotion: Exiting method getWatchListUserSavedSearchList: returning watchListUserSavedSearchList: " + WatchListUserSavedSearchList, AppsLogger.FINEST);
            }
            return WatchListUserSavedSearchList;
        }     
    
15.3.4.11.1 How to Promote a User-Saved Search to the Watchlist

Follow these steps to integrate the ATK task flow to promote saved searches to the Watchlist.

Note:

If you already have implemented promoting the user-saved search to the Watchlist, see Additional Steps for Existing Consumers.

  1. Ensure the AdfAtkWathcListPublicUi.jar file is available (usually in the fusionapps/jlib directory).

  2. Start JDeveloper and open the .jspx or .jsff page containing the query region whose saved searches have to be promoted.

  3. In the query region, add a toolbar facet.

    1. Right-click the component.

    2. In the menu that opens, select Facets-Query.

    3. From the submenu, select Toolbar, as shown inFigure 15-13.

      Figure 15-13 Adding Toolbar Facet to Query Region

      Adding Toolbar Facet to Query Region
  4. In the toolbar facet of the query region, drag and drop an ADF Toolbar component, such as Toolbar (ADF Faces.Common Components) shown in Figure 15-14, onto the page.

    Figure 15-14 Adding an ADF Toolbar Component

    Adding an ADF Toolbar Component

    The toolbar facet in the Source view will look similar to:

    <f:facet name="toolbar">
      <af:group id="g1">
        <af:toolbox id="t1">
          <af:region value="#{bindings.AtkWatchlistUserSavedSearchPromotionTF1.regionModel}"
                     id="r7"/>
        </af:toolbox>
        <af:toolbar id="t2"/>
      </af:group>
    </f:facet>
    
  5. Open the Resource Palette and create a File System connection to the directory containing the AdfAtkWatchListPublicUI.jar file, as shown in Figure 15-15.

    Figure 15-15 Creating the File System Connection

    Creating the File System Connection
  6. Expand the connection node and the ADF library node in the Resource Palette as shown in Figure 15-16.

    Figure 15-16 Expanding the Connection Node

    Expanding the Connection Node

    Once the ADF Task Flows node is expanded, you should see two task flows. The task flow AtkWatchlistUserSavedSearchPromotionTF is the one to be used.

  7. Drag and drop the AtkWatchlistUserSavedSearchPromotionTF task flow as a region into the toolbar component (present in the query region toolbar facet), created in the previous steps. As soon as the task flow is dropped onto the page, the Edit Task Flow Binding dialog is displayed. Enter the following values for the mandatory parameters.

    • categoryCode: Provide the WATCHLIST_CATEGORY_CODE that has been seeded in the ATK tables.

    • watchlistItemCode: Provide the WATCHLIST_ITEM_CODE provided while creating the Watchlist setup data.

    • userSavedSearchList: This represents the model object of the query region. To populate this field:

      1. Select the userSavedSearchList input field, click the small "v" icon present at the end of the field and select the Expression Builder option.

      2. Select the value from the Java method shown in Example 15-12. In this case, the value is watchListUserSavedSearchList, found in ADF Managed Beans > backingBeanScope > searchOrderScheduleBackingBean > watchListUserSavedSearchList.

        The Expression will be:

        #{backingBeanScope.searchOrderScheduleBackingBean.watchListUserSavedSearchList}
        
      3. Click OK to insert the value in the userSavedSearchList field.

    • internalCriteriaName: This represents the ViewCriteria Name of the search binding executable of the query region present in the UI page. To populate this field, follow the same steps as you did to populate the userSavedSearchList field, but select internalCriteriaName. Also see Additional Steps for Existing Consumers.

    When you are finished, the Edit Task Flow Binding dialog will resemble Figure 15-17.

    Figure 15-17 Completed Edit Task Flow Binding Dialog

    Completed Edit Task Flow Binding Dialog
  8. Click OK. This creates a region component in the UI page, as shown in Figure 15-18.

    Figure 15-18 Created Region Component

    Created Region Component
  9. Open the page definition file and select the executable associated with the Watchlist-related task flow.

  10. Open the Property Inspector and set the Refresh field to ifNeeded, as shown in Figure 15-19. The ATK saved search promotion task flow has to be refreshed each time the query model changes. This step ensures that the task flow is refreshed whenever the query model changes.

    Figure 15-19 Setting Refresh to ifNeeded

    Setting Refresh to ifNeeded
  11. Add a task flow security permission to the AtkWatchlistUserSavedSearchPromotionTF task flow in the jazn-data.xml file.

    1. Open the jazn-data.xml file and select the ADF Policies tab.

    2. From the Task Flow list, select AtkWatchlistUserSavedSearchPromotionTF, grant it to an appropriate role, and select appropriate actions as shown in Figure 15-20.

      Figure 15-20 Adding Security Permissions to jazn_data.xml

      Adding Security Permissions to jazn_data.xml
  12. Run the UI page. In the toolbar facet of the query region, there will be a Watchlist Options button, as shown in Figure 15-21.

    Figure 15-21 Watchlist Options Button in Toolbar Facet

    Watchlist Options Button in Toolbar Facet

    When you click the button, a popup with the list of all saved searches is displayed, as shown in Figure 15-22.

    Figure 15-22 List of Saved Searches

    List of Saved Searches

Additional Steps for Existing Consumers

If you already have implemented promoting Saved Search to the ATK Watchlist, there are four additional steps.

  • In your pageDef, change the WatchList task flow parameter called queryModel from:

    <parameter id="queryModel"     value="#{bindings.ExistingCriteria.queryModel}"/>
    

    to:

    <parameter id="userSavedSearchList"
      value="#{backingBeanScope.YourBean.watchListUserSavedSearchList}"/>
    
  • Use the public List<String> getWatchListUserSavedSearchList() Java method by passing the QueryModel binding of your af:query.

  • Change the old queryBinding parameter to the new internalCriteriaName parameter. For example, change:

    parameter id="queryBinding" value="#{bindings.SearchPageVOCriteriaQuery}"
    

    to:

    parameter id="internalCriteriaName" value="#{backingBeanScope.searchRelatedBean.internalCriteriaName}"
    
  • In someBackingBeanScopeBean.java, such as the one you created in Example 15-12, add the two methods shown in Example 15-13.

    Example 15-13 Additions to the backingBeanScopeBean

    import javax.el.ExpressionFactory;
    import javax.el.MethodExpression;
    import javax.el.ValueExpression;
    import javax.faces.context.FacesContext;
    import oracle.adf.model.binding.DCBindingContainer;
    import oracle.jbo.uicli.binding.JUSearchBindingCustomizer;
     
      public Object evaluateEL(String expr)
      {
          FacesContext facesContext=FacesContext.getCurrentInstance();
          ExpressionFactory exprFactory=facesContext.getApplication().getExpressionFactory();
          ValueExpression valueExpr=exprFactory.createValueExpression(facesContext.getELContext(), expr, Object.class);
          return valueExpr.getValue(facesContext.getELContext());
      }
     
      public String getInternalCriteriaName() {
         if (AppsLogger.isEnabled(AppsLogger.FINEST)) {
           AppsLogger.write(this, "Watchlist saved search promotion: Entering method getInternalCriteriaName", AppsLogger.FINEST);
         }
         String queryBinding = "#{bindings.SearchPageVOCriteriaQuery}";
         DCBindingContainer  searchBinding = (DCBindingContainer)evaluateEL(queryBinding);       
         internalCriteriaName = JUSearchBindingCustomizer.getCriteriaName(searchBinding);
         if (AppsLogger.isEnabled(AppsLogger.FINEST)) {
           AppsLogger.write(this, "Watchlist saved search promotion: Exiting method getInternalCriteriaName with return value for internalCriteriaName: " + internalCriteriaName, AppsLogger.FINEST);
         }     
         return internalCriteriaName;
      } 
    

    Note: In someBackingBeanScopeBean.getInternalCriteriaName(), the queryBinding variable in the first line is the one you see in af:query. For example, af:query queryListener="#{bindings.SearchPageVOCriteriaQuery.processQuery}" Just take the QueryBinding, #{bindings.SearchPageVOCriteriaQuery}.

15.3.4.12 Code Task Flows to Accept Parameters (All except HUMAN_TASK)

If you have seeded the information properly, your normal task flows should work when drilleddown to from the Watchlist portlet.

15.3.4.12.1 Saved Search

For saved search Watchlist items, you will want the drilldown to load a specific saved search by default.

One function of the Watchlist portlet will be to take a user to the corresponding action area when the user clicks a Watchlist item. For saved searches, the desired functionality is to open the task flow containing the saved search panel and by default, show the clicked saved search.

On the portlet, upon clicking the link, code will put the proper ViewCriteria name into the PageFlowScope with the parameter name vcName.

When loaded, the destination task flow will have two tasks:

  • Look into the PageFlowScope to retrieve the ViewCriteriaName.

  • Obtain the RichQuery object, and apply the ViewCriteriaName to it, if one is given.

You will be concerned with implementing the two steps for the destination task flow. First, you can retrieve the ViewCriteriaName from the PageFlowScope with the code shown in Example 15-14.

Example 15-14 Retrieving the ViewCriteriaName from the PageFlowScope

Map pfs = RequestContext.getCurrentInstance().getPageFlowScope(); String vcName = (String) pfs.get("vcName");

Second, you can use the code shown in Example 15-15 to apply the ViewCriteria to the search panel. If no ViewCriteria was passed, the code loads the default ViewCriteria.

Example 15-15 Applying ViewCriteria to the Search Panel

if (vcName == null || vcName.equals("")) {
        // If no ViewCriteria is given, load default VC
        DCBindingContainer dcbc = 
(DCBindingContainer)BindingContext.getCurrent()
                .getCurrentBindingsEntry();
FacesCtrlSearchBinding fcsb = 
(FacesCtrlSearchBinding)dcbc
.findExecutableBinding("ImplicitViewCriteriaQuery");
FacesCtrlSearchDef def = (FacesCtrlSearchDef)fcsb.getDef();
DCParameterDef paramDef = 
(DCParameterDef)def.getParameterDef(
JUSearchBindingCustomizer.PARAMCRITERIA);
fcsb.evaluateParameter(paramDef.getExpression(),false));
} else {
        QueryModel model = search_query.getModel();
        QueryDescriptor selDescriptor = model.create(vcName, null);
if (selDescriptor != null) {
model.setCurrentDescriptor(selDescriptor);
}
BindingContainer bindings = 
BindingContext.getCurrent().getCurrentBindingsEntry();
OperationBinding method = (OperationBinding) 
bindings.getControlBinding("applyViewCriteriaByName");
method.getParamsMap().put("name", vcName);
method.execute();
}

This code should be run once upon loading the destination task flow. One solution is to connect it to the rendered property of the search panel, and use a static variable to ensure that it only runs once.

15.3.4.13 Import Watchlist UI JAR File in User Interface Project

There is a link in the UI Shell for Watchlist in the Global Area. To make it work, the user interface project must include these Watchlist UI JAR files: AdfAtkWatchListPublicUI and its dependent model JAR file AdfAtkWatchListProtectedModel.

15.3.4.14 Additional Entries for Standalone Deployment

These entries are required for the Watchlist service and UI to be able to work in a standalone deployment.

  • Add this entry in the ejb-jar.xml file in your service project that contains the watchlist service next to the similar entry for ApplicationDB. You need resource-ref entries for both ApplicationDB and AppMasterDB:

    <resource-ref> 
      <res-ref-name>jdbc/AppMasterDBDS</res-ref-name> 
      <res-type>javax.sql.DataSource</res-type> 
      <res-auth>Container</res-auth> 
    </resource-ref>
    
  • Add this entry in the web.xml file in your SuperWeb project next to the similar entry for ApplicationDB. You need resource-ref entries for both ApplicationDB and AppMasterDB:

    <resource-ref> 
      <res-ref-name>jdbc/AppMasterDBDS</res-ref-name> 
      <res-type>javax.sql.DataSource</res-type> 
      <res-auth>Container</res-auth> 
    </resource-ref>
    
  • The connections.xml file should have a valid database entry for AppMasterDB.

15.4 Implementing Group Spaces

Group Spaces bundle all the collaboration tools and provide an easy way for users to create their own ad hoc collaborative groups around a project or business artifact.

This section describes how to implement the Group Spaces functionality that is available in UI Shell.

15.4.1 Assumptions

These assumptions are made:

  • The implementation is occurring in a label that is either dependent on ATGPF_MAIN or uptakes ATGPF_MAIN on a regular basis.

  • The spaces application and the JDeveloper Standalone WebLogic Server that would run the application have the requisite setup done.

  • The consuming applications are secure. Group Spaces functionality attempts to retrieve the group spaces for the logged-on user. Without a secure application, this functionality would fail.

15.4.2 How to Implement Group Spaces

Follow these steps to implement Group Spaces.

  1. Ensure the Oracle WebCenter Portal Spaces Client library, spaces-webservice-client.jar, has been added to the Project.

  2. Define an application connection to point to the URL of the WebCenter Portal Spaces WebService. To do this:

    1. Right-click Connections in the Application Resource palette.

    2. Choose New Connection > URL.

    3. Enter the value $HOST:$PORT/webcenter/SpacesWebService, where $HOST and $PORT are the hostname and the port on which the spaces application is running.

    4. Save this connection with the name SpacesWebServiceEndpoint.

  3. To make a homepage tab appear within UI Shell, deploy the Functional Setup Manager application.

15.4.3 Overview of Group Spaces Functionality

The Group Spaces functionality implements these features:

  • When the Group Spaces link is clicked, a popup displays the logged-in user's Group Spaces.

  • When the user clicks a Group Space from the list, the Group Space's home page is opened in an iFrame. This iFrame is rendered within a Home Page tab called WebCenter. The Group Space is opened suppressing the WebCenter Portal chrome but will still render all the tabs within that Group Space. (Note: Chrome is a term for the visible graphical interface features of an application.) This chrome level suppresses the WebCenter Portal chrome but will still render all the tabs within that Group Space.

  • When the user clicks View All Group Spaces, the same UI as the My Group Spaces in the spaces application is rendered. This is also rendered as an iFrame within the WebCenter Portal HomePage tab where it suppresses the chrome as well as the top level WebCenter Portal tabs.

15.4.4 How to Pass a Chromeless Template

When navigating to the WebCenter Portal home page, a WebCenter Portal template that does not contain the header chrome is desired. This can be done by appending &wc.pageTemplate=oracle.webcenter.spaces.siteTemplate.gsContent.

Pass this parameter when navigating to a Group Space from the Group Spaces global dialog, Tag Center, Global Search, or an Activity Stream link.

Use a question mark (?) instead of an ampersand (&) if this is the only request parameter for that URL.

15.5 Implementing Activity Streams and Business Events

Activity Streams is a feature provided by the WebCenter Portal. Use Activity Streams to capture changes and publish Activity messages. Customer Relations Management (CRM), in particular, makes heavy use of this feature to keep abreast of service requests and opportunities. Users subscribe to Activity Streams by using the Activity Streams user interface.

For business events, Activities are shown only to users who subscribe to the stream and who have the necessary security access.

Activity Streams can be connected to:

This section is concerned only with business objects.

15.5.1 Introduction to WebCenter Portal Activities

A WebCenter Portal Activity is comprised of the following:

  • Actors - The user who performed the action that triggered the business event. For Oracle Fusion Applications, this will be the userid fetched from the user session.

  • ActivityType - The type of Activity to be published. This defines the format of the Activity message.

  • Objects - The objects associated with the Activity. There could be multiple objects associated with an Activity but for business events, only the event source is used as an object.

WebCenter Portal Activities are defined in the service-definition.xml file. The scope of service_definition.xml is per business object. The service ID attribute should match the name of the entity object. The service-definition.xml file contains ActivityTypes, ObjectTypes and resource-view definitions. An ActivityType must be defined for every business event on the entity object. The type name should match the business event's name. The messageFormatKey attribute in the ActivityType element points to a message key in a Resource Bundle. It defines the format of the message displayed in the Activity Stream UI. These tokens are supported in a message.

  • {actor[0]}: Replaced by the display name of the user who triggered the event.

  • {object[0]}: Replaced by the value of the attribute in the event payload whose attribute name matches the object type name.

  • {custom[attr1].value}: Replaced by the value of the attr1 attribute in the event's payload.

The message format would look similar to:

{actor[0]} updated Opportunity {object[0]} status to {custom[status].value}

15.5.2 How to Publish Business Events to Activities

ADF Business Components business events are, by default, published to SOA Event Delivery Network (EDN). Applications Core implements a BusinessEventAdapter to listen to these events, transition them to Activities, and asynchronously publish them to the ActivitiyStream Service. This adapter is a singleton per application and publishes the business events raised to the ActivityService in the order they are produced. A business event is published as an Activity only when an ActivityType matching the name of the event is found in the service definition for the business object.

While mapping a business event to an Activity, keep these notes in mind:

  • There is one-to-one mapping between an Activity Service definition and a business object. The service ID attribute in the service-definition.xml file should match the Entity name.

  • The ActivityType name should match the name of the business event.

  • Define an ObjectType with the name attribute matching an attribute name in the payload. This attribute value will replace the {object[0]} token in the message format. WebCenter Portal supports multiple object types for an Activity, but for business events-related Activities, only one Object that corresponds to the event source is supported. The Object type name should match the name of the attribute whose value should be displayed in the hyper link for the object.

  • Define a message format using tokens for Actor, Object and customAttributes. The custom attribute names used in the token should match the attribute names in the payload.

  • In the Activity message displayed in the UI, only Actor and Object display values will be rendered as hyper links. If an Activity involves multiple objects, hyper links will be supported only for the event source object. Multiple attributes from the event payload can be referenced in the message.

  • The hyper link for the object allows users to navigate to the business object's work area. The target page for navigation can be configured through the resource-view element in the service-definition.xml file.

15.5.3 How to Publish Activities Using a Programmatic API

For certain scenarios, Oracle Fusion Applications are required to publish Activities for model changes that are not based on entity objects. Since Oracle ADF Business Components business events are based on entity objects, it is not possible to use these events for publishing Activities for non entity object-based model changes. For such scenarios, product teams could use the Applications Core API shown in Example 15-16 to programmatically publish Activities to the ActivityStream service.

BusinessActivityPublisher

This class provides the publishActivity API that can be used to publish Activities asynchronously. This is a singleton per Java EE application. An instance of this class can be obtained using the getInstance API. This lets product teams define such things as ActivityTypes, ObjectTypes, and resource-view definitions, declaratively in the service-definition.xml file, similar to business event-related activities.This would allow product teams to follow the same mechanism to define and publish Activities for both entity object and non-entity object-based model changes with very little code changes.

Example 15-16 BusinessActivityPublisher.java

/**
 * This class is responsible for publishing business events as WebCenter Portal Activities to
 * the ActivityStreaming service. This is a singleton per Java EE application.
 * An instance of this object is obtained using the getInstance() method. This class
 * transforms business events into Activities and publishes them to Activity
 * Service asynchronously. Resources held by the class are released by using
 * release() method. In Java EE container, release is done by Applications Core when 
 * the application is undeployed or stopped.
 */
public class BusinessActivityPublisher
{
    /**
     * Returns and instance of BusinessActivityPublisher if one exists or
     * creates anew one.
     * @return
     */
    public synchronized static BusinessActivityPublisher getInstance()
 
    /**
     * Queues the Activity for publishing. The queued activities are published
     * to the Activity Streaming service asynchronously if there is a matching
     * ActivityType defined for the source business event. If no matching
     * ActivityType is found in the service-definition.xml corresponding to the
     * source entity object, the activity is ignored.
     * @param activity
     */
    public void publishActivity(BusinessActivity activity)
 
    /**
     * Should be called during App undeploy to stop the publisher thread.
     * In a Java EE container, this method is called by Applications Core
     * ServletContextListener.
     */
    public void release()

BusinessActivity Class

This is an abstract class that is used to represent an Activity corresponding to a business event. BusinessActivityPublisher:publishActivity() takes an instance of this class as a parameter. You would implement an instance of this class to encapsulate the details of the Activity corresponding to the non entity object-based model changes and invoke the publishActivity API with this as a parameter. BusinessActivityPublisher will find the matching ActivityType and ObjectType defined for this Activity in service-definition.xml and publish the Activity to the ActivityStreaming Service asynchronously. Details of the API on this class are shown in Example 15-17.

Example 15-17 BusinessActivity.java

/**
   * Name of the ActivityType defined in service-definition that
   * corresponds to serviceId returned by getServiceId().
   * @return Name of the ActivityType
   */
  public String getName()
 
  /**
   * ID of the service-definition containing the metadata for this
   * Activity.
   * @return serviceId
   */
  public abstract String getServiceId();
 
  /**
   * Array of GUIDs for Actors of the Activity.
   * @return array of guids for the Actors.
   */
  public abstract String[] getActors();
 
  /**
   * This api will return  additional service ids
   * @return Array of ServiceIds
   */
  public String[] getAdditionalServiceIds(){ return null};
 
  /**
   * This attr provides a "," separated list of object type
   * names associated with a particular Activity.
   * @return
   */
  protected String getActivityObjectTypeNames(){
   return null;
  } 
 
  **
   * Payload for the Activity. Every attribute that is part of this payload is
   * persisted in WC as custom attribute of the Activity Object so only
   * attributes needed for the Activity Message should be added to the payload
   * to avoid performance overhead.
   * The payload typically  contains:
   * 1. Attribute(s) whose name matches the object-type name attribute in
   *    service-definition. This value is used in generating the object-id
   *    of the object referenced in the Activity Stream message.
   * 2. All the attributes referenced in the Message format using {custom}
   *    token.
   * @return a map containing the attribute names and their values needed to
   * display the Activity Message for this Activity.
   */
  public abstract Map getPayload();

BusinessActivity

This is an abstract class that is used to represent an Activity corresponding to a business event. BusinessActivityPublisher:publishActivity() takes an instance of this class as a parameter. You would implement an instance of this class to encapsulate the details of the Activity corresponding to the non entity object-based model changes and invoke the publishActivity API with this as a parameter. BusinessActivityPublisher will find the matching ActivityType and ObjectType defined for this Activity in the service-definition.xml file and publish the Activity to the ActivityStreaming Service asynchronously. Details of the API on this class are shown in Example 15-18.

Example 15-18 BusinessActivity.java

/**
  * Name of the ActivityType defined in service-definition that
  * corresponds to serviceId returned by getServiceId().
  * @return Name of the ActivityType
  */
 public String getName()
 
 /**
  * ID of the service-definition containing the metadata for this
  * Activity.
  * @return serviceId
  */
 public abstract String getServiceId();
 
 /**
  * Array of GUIDs for Actors of the Activity.
  * @return array of guids for the Actors.
  */
 public abstract String[] getActors();
 
 /**
  * This api will return  additional service ids
  * @return Array of ServiceIds
  */
 public String[] getAdditionalServiceIds(){ return null};
 
 /**
  * This attr provides a "," separated list of object type
  * names associated with a particular Activity.
  * @return
  */
 protected String getActivityObjectTypeNames(){
  return null;
 } 
 
 **
  * Payload for the Activity. Every attribute that is part of this payload is
  * persisted in WC as custom attribute of the Activity Object so only
  * attributes needed for the Activity Message should be added to the payload
  * to avoid performance overhead.
  * The payload typically  contains:
  * 1. Attribute(s) whose name matches the object-type name attribute in
  *    service-definition. This value is used in generating the object-id
  *    of the object referenced in the Activity Stream message.
  * 2. All the attributes referenced in the Message format using {custom}
  *    token.
  * @return a map containing the attribute names and their values needed to
  * display the Activity Message for this Activity.
  */
 public abstract Map getPayload();

15.5.4 How to Implement Activity Streams

This section provides details about the steps involved in integrating this feature with Oracle Fusion Applications.

15.5.4.1 Defining and Publishing Business Events in JDeveloper

To define a business event, follow these steps:

  1. In the Application Navigator, double-click an entity object.

  2. In the overview editor, click the business events navigation tab.

  3. On the business events page, expand the Event Publication section and click the Edit event publications icon.

  4. In the Edit Event Publications dialog, click New to create a new event.

  5. Double-click the new cell in the Event column, and select the appropriate event.

  6. Double-click the corresponding cell in the Event Point column, and select the appropriate event point action.

  7. You optionally can define conditions for raising the event using the Raise Conditions table.

  8. Click OK.

An event definition in the Entity XML file would look similar to:

<EventDef  Name="OpportunityStatusUpdate">
  <Payload>
    <PayloadItem AttrName="OpptyId"/>
    <PayloadItem AttrName="Status"/>
    <PayloadItem AttrName="Customer.CustomerId"/>
  </Payload>
</EventDef>

15.5.4.2 Overriding isActivityPublishingEnabled() to Enable Activity Publishing

By default, business events are not published as Activities. You should override the isActivityPublishingEnabled() method to enable Activity publishing for an entity object. Table 15-4 shows the details about the APIs exposed in OAEntityImpl that you can override.

Note that, except for the isActivityPublishingEnabled() method, other methods mentioned in Table 15-4 should be avoided in favor of transient attributes specified in Section 15.5.4.3, "Defining Activity Attributes Declaratively."

Table 15-4 Overriding isActivityPublishingEnabled()

Method Return Type Description Optional/Required Corresponding Declarative Transient Attribute (See Section 15.5.4.3)

isActivityPublishingEnabled()

boolean

By default the base class implementation returns false. This will enable activity publishing for this entity object.

Required

None

getActivityActorsGUIDs()

String []

This can be overridden to provide an array of GUIDs for the Actors involved with the activity. By default, the framework will use the GUID of the user currently logged in when the business event is raised.

Optional

WCActivityActorGuid1, WCActivityActorGuid2

getActivityStreamServiceId()

String

This returns the service ID to be used to publish the activities for the business events raised for this entity. By default this returns null. When null is returned, the service ID defaults to the full name of the entity object.

Optional

WCActivityServiceId

getAdditionalServiceIds()

String []

Override this API to support publishing multiple Activities in response to a single event. So additional service IDs can be passed for a single activity.

Optional

WCAdditionalActivityServiceId1, WCAdditionalActivityServiceId2

getActivityObjectTypeNames()

String

This API can be overridden to return multiple object type names. Values provided should be a comma-separated list of object type names associated with a particular Activity.

The first object-type in this string will be used to create the custom attributes needed for the primary object. When creating the primary object for an Activity, the object-type of the first object listed in the service-definition.xml file should be used even though the custom attributes used to construct this object are fetched from a different object-type based on getActivityObjectTypeNames() or WCActivityObjectTypeNames. This is necessary for the follow model to work. The order of the objects in this array can be used to reference the objects in an Activity message format string.

Optional

WCActivityObjectTypeNames


15.5.4.3 Defining Activity Attributes Declaratively

Some of the attributes, such as Actor, Service Ids and Additional Service Ids, can be passed as a part of the payload. The basic process steps are:

  • Define a transient attribute in the entity object.

  • Give a default value to the transient attribute.

  • Include the transient attribute as a part of the payload.

The different transient attributes that can be passed with the payload are shown in Table 15-5.

Table 15-5 Transient Attributes that Can Be Passed with the Payload

Attribute Type Description Sample Value

WCActivityServiceId

String

This attribute's value is used to identify the business object service to be associated with the Activity.

oracle.apps.crmdemo.model.OpportunityEO

WCAdditionalActivityServiceId1

String

This attribute's value is used to identify any additional service that must be associated with the Activity.

Values are similar to those of WCActivityServiceId

WCAdditionalActivityServiceId2

String

This attribute's value is used to identify any additional service that must be associated with the Activity.

Values are similar to those of WCActivityServiceId

WCActivityActorGuid1

String

This attribute's value is used to identify any actor that must be associated with the Activity if the default actor value must be overridden. For instance, in the message it can be accessed as actor[0]

<User_GUID>

WCActivityActorGuid2

String

This attribute's value is used to identify any actor that must be associated with the Activity if the default actor value must be overridden. For instance, in the message it can be accessed as actor[1]

<User_GUID>

WCActivityObjectTypeNames

String

This attribute should provide a comma-separated list of object-type names associated with a particular Activity. Programmatically getActivityObjectTypeNames() API in the entity object's EntityImpl.

The first object- type in this string will be used to create the custom attributes needed for the primary object. When creating the primary object for an Activity, the object type of the first object listed in the service-definition.xml file should be used even though the custom attributes used to construct this object are fetched from a different object type based on getActivityObjectTypeNames() or WCActivityObjectTypeNames. This is necessary for the follow model to work.

The order of the objects in this array can be used to reference the objects in the Activity message format string.

Emp, Dept


15.5.5 How to Define Activities

Defining Activities requires:

  • Adding the ActivityStream UI task flow

  • Defining Activities in the service-definition.xml file

15.5.5.1 Adding the ActivityStream UI Task Flow

To add the ActivityStream task flow:

  1. Ensure your user interface project includes the Oracle WebCenter Portal Activity Streaming Service library in the Libraries and Classpath section in the project properties dialog.

  2. From Resource Catalog > TaskFlows, drag and drop either an "Activity Stream" or "Activity Stream Summary - View" task flow onto the page where you want to display the Activity Stream UI.

  3. Set the taskFlow resourceId parameter to #{securityContext.userName}. This will tie the task flow to the current user at runtime.

  4. For additional details about the Activity Stream task flow, see the chapters in the "Working with the People Connections Service" partition in the Oracle Fusion Middleware Developer's Guide for Oracle WebCenter Portal.

15.5.5.2 Defining Activities in the service-definition.xml File

The default location of the service-definition.xml file is under META-INF in the project. For Oracle Fusion Applications, this file will be stored in MDS so you need to put it into a directory that can be added to your Metadata Archive (MAR) file.

The standardized location that all applications should use is:

<app>/<lba>/<product>/<*project*>/*meta/oracle/apps/meta*/<lba>/<product>/service-definition.xml

The name must be unique, such as:

helpPortal/atk/helpPortal/model/meta/oracle/apps/meta/atk/helpPortal/service-definition.xml

To define Activities in the service-definition.xml file, follow these steps.

  1. If necessary, add the directory to the application's MAR profile. To add a MAR, select Application > Application Properties > Deployment. In the dialog that is displayed, select the MAR file and click Edit.

  2. In the Edit dialog, select User Metadata and click Add. Browse to the metadata directory that was just added and click OK.

  3. Set the id attribute on the service-definition element to the entity object name for which you want to define the Activities.

    <service-definition xmlns="http://xmlns.oracle.com/webcenter/framework/service"
                  id="oracle.apps.crmdemo.model.OpportunityEO"
                  version="11.1.1.0.0">
    
  4. Define an activity type for every business event in the entity object for which you want to display the Activities in the Activity Stream UI. Ensure the event name of the entity object matches the activity-type name attribute value.

    <activity-types>
      <generic-activity-category name="UPDATE">
        <activity-type name="OpportunityStatusUpdate"
                       displayName="Opportunity Status Update"
                       description="Opportunity Status Update"
                       messageFormatKey="OPPTY_STATUS_UPDATED"
                       iconURL=""
                       defaultPermissionLevel="SHARED"/>
      </generic-activity-category>
    </activity-types>
    
  5. Set message format strings.

    Each activity-type should have a message format defined. The message format string can be translated and is stored in a Resource Bundle or an XLIFF bundle. Oracle Fusion Applications uses XLIFF bundles to store the Activity message format strings. The activity-type element in the service-definition.xml file has messageFormatKey attributes that are used to refer to the format strings in the XLIFF bundle.

    Activity Stream supports only Java Resource Bundles. The Common String Repository is used for the message format strings.

    These attributes are supported on the activity-type element:

    • messageFormatKey - Used on the Activity Stream full view task flow.

    • summaryByListMessageFormatKey - Used in the summary view Activity Stream task flow.

    • summaryByCountMessageFormatKey - Used in the summary view task flow.

    messageFormatKey

    The value of this attribute points to the key defined in the Resource Bundle. These tokens are supported in the message format string.

    • {actor[0]}: Replaced by the display name of the user who triggered the event.

    • {object[0]}: Replaced by the value of the attribute in the event payload whose attribute name matches the object type name.

    • {custom[attr1].value}: Replaced by the value of the attr1 attribute in the event's payload.

    The following sample uses the Java Resource Bundle class:

    <resource-bundle-class>oracle.apps.crm.OpportunityResourceBundle</resource-bundle-class>
     <activity-types>
       <generic-activity-category name="OPPTYUPDATE">
         <activity-type name="OpptyStatusUpdate"
                        displayName="OPPTY_UPDATE"
                        description="OPPTY_UPDATE_DESCRIPTION"
                        messageFormatKey="OPPTY_STATUS_UPDATED"
                        defaultPermissionLevel="SHARED"/>
        </generic-activity-category>
     </activity-types>
    

    In OpportunityResourceBundle, the OPPTY_STATUS_UPDATED key is defined as:

    {"OPPTY_STATUS_UPDATED", "{actor\[0\]} updated {object\[0\]} status to {custom\['status'\].value}"}
    

    summaryByListMessageFormatKey and summaryByCountMessageFormatKey

    These attributes are used only when the Activity Stream summarized view task flow is used. The summarized view task flow is used on the portrait page in My Activities and Network Activities mini cards. In summarized view, the Activity messages are summarized or grouped based on an Activity Type. For instance, if multiple Activities of the same type are published, they are combined and displayed as a single Activity message. Within the group of Activities of the same type, the following algorithm is used to generate summarized messages:

    1. Summarize activities by finding a common object referenced in the Activity.

    2. Summarize or aggregate the Actors either by listing them if there are three or fewer, or by counting them if there more than three.

    3. For remaining activities, summarize by finding a common Actor. Summarize or aggregate the objects either by listing them if there are three or fewer, or by counting them if there are more than three.

    For example, note the following activities:

    1. James updated Project Alpha tasks.

    2. Viju updated Project Alpha tasks.

    3. Ling updated Project Alpha tasks.

    4. Monty updated Oppty 200 laptops status

    5. Monty updated Oppty Solaris workstations status

    6. Monty updated Oppty 2 DB machines status.

    In the summarized view, the Activities are summarized as follows:

    • Activities a-c: James, Viju, Ling updated Project Alpha tasks.

    • Activities d-f: Monty updated 200 laptops, Solaris workstations, 2 DB machines opportunities status.

    Example 15-19 shows sample format strings for the preceding scenario.

    Example 15-19 Sample Format Strings for a Summarized View

    <resource-bundle-class>oracle.apps.crm.OpportunityResourceBundle</resource-bundle-class>
     <activity-types>
       <generic-activity-category name="OPPTYUPDATE">
         <activity-type name="OpptyStatusUpdate"
                   displayName="OPPTY_UPDATE"
                   description="OPPTY_UPDATE_DESCRIPTION"
                   messageFormatKey="OPPTY_STATUS_UPDATED"
                   summaryByListMessageFormatKey="OPPTY_STATUS_UPDATED_SUMMARY_LIST"
                   summaryByCountMessageFormatKey="OPPTY_STATUS_UPDATED_SUMMARY_CNT"
                   defaultPermissionLevel="SHARED"/>
        </generic-activity-category>
     </activity-types>
    

    In the OpportunityResourceBundle, the keys are defined as:

    {"OPPTY_STATUS_UPDATED_SUMMARY_LIST", "{actor\[0\]} updated status for opportunity {object\[0\]} }"}
    {"OPPTY_STATUS_UPDATED_SUMMARY_CNT", "{actor\[0\]} updated {object\[0\].count} opportunities status"}
    
  6. Define an object type for the entity object that is the source of the events. Even though Oracle WebCenter Portal supports multiple object types, for Oracle Fusion Applications, only one object type that corresponds to the source of the events is supported. The value of the name attribute should match the name of the attribute in the business event's payload. This attribute's value will be used as the display name of the object when displayed in the Activity message. The primary key of the event source will be used as the object ID.

    <object-types>
       <object-type name="OpptyId"
                    displayName="Opportunity Object"
                    description="Opportunity Object"
                    iconURL="">
       </object-type>
    </object-types>
    
  7. The ObjectType custom attributes can be used to provide additional metadata for handling business object references in Activity Stream messages. The custom attributes shown in Table 15-6 will be used.

    Table 15-6 ObjectType Custom Attributes

    Name Description

    service-ref-id

    ID of the service-definition of a business object referenced in the Activity message of the current business object. This is used when an Activity message contains multiple object references and is used to reference the serviceId of some other business object.

    object-id-attr

    The name of the attribute in the business event payload that should be used as the object-id for an Activity object. Typically this corresponds to the primary key attribute of a business object. If this attribute is not specified, the object-type element's name attribute is used as the default.

    display-name-attr

    The name of the attribute in the business event payload that should be used as the display name of the Activity object. This attribute's value will be used to replace the {object} token in the Activity's message format.


    <object-type>
      <custom-attributes>
        <custom-attribute name="service-ref-id" defaultValue="oracle.apps.crm.model.OpptyEO"/>
        <custom-attribute name="object-id-attr" defaultValue="opptyId"/>
        <custom-attribute name="display-name-attr" defaultValue="opptyName"/>
      </custom-attributes>
    </object-type>
    
  8. Define resource view handler parameters to allow custom navigation for links rendered in the Activity message. Navigation from the Actor link in the Activity message navigates to the user's portrait page. Custom navigation to the business object workarea is supported. Important fields include:

    • taskFlowId: The task flow where you want to go.

    • resourceParamList: The list of parameters that you want to pass to the task flow. For example, if a business object task flow takes the opptyId parameter, in resourceParamList you should specify "opptyId". If multiple parameters are required, the parameters should be separated by a semi-colon (;), for example "opptyId;opptyType". When the hyper link is clicked, parameters opptyId="oppty id value" and opptyType="type value" will be passed as input parameters to the task flow.

      <resource-view taskFlowId="/WEB-INF/OpportunityTF.xml#OpportunityTF">
        <parameters>
          <parameter name="viewId" value="Opportunity"/>
          <parameter name="webApp" value="CRMApp"/>
          <parameter name="pageParametersList" value=""/>
          <parameter name="taskParametersList" value=""/>
          <parameter name="resourceParamList" value="opptyId"/>
        </parameters>
      </resource-view>
      

      Custom navigation is handled by the Applications Core ResourceViewHandler registered in the adf-config.xml file. You must add this entry to all adf-config.xml files:

      <wpsC:adf-service-config xmlns:wpsC="http://xmlns.oracle.com/webcenter/framework/service">
          <resource-handler class="oracle.apps.fnd.applcore.tags.handler.FndResourceActionViewHandler"/>
      </wpsC:adf-service-config>
      

15.5.6 How to Implement Comments and Likes

Commenting allows users to comment on objects that are created or published by various users on the site, and engage in discussions revolving around those objects using replies to comments and comments upon comments. This feature in Activity Stream allows users to comment on a specific Activity related to a object.

The Likes feature allows users to express their liking for any object in the system to which they have access. This feature is exposed in message boards, Activity Streams, doclib and replies on topics in discussion forums. In Activity Stream, this feature allows users to indicate if they like a particular Activity.

To enable Comments and Likes for a service, add these Activity Types to the service-definitio.xml file:

<activity-type name="postComment"
               messageFormatKey="ACTIVITY_COMMENT_STATUS"/>
<activity-type name="expressLike"
               messageFormatKey="ACTIVITY_LIKE_STATUS"/>

Ensure the activity-type names are as shown. The messageFormatKey values refer to the ResourceBundle keys that provide strings displayed for "comments" and "likes" links displayed in the Activity message.

15.5.7 How to Implement Follow for an Object

Users will be able to see Activity messages belonging to the business objects they are following. Users should either explicitly follow a business object, or you should provide a way for users to follow certain business objects implicitly. A business object can be followed for a user by using the Oracle WebCenter Portal Follow API. A sample implementation of the Follow model is shown in Example 15-20.

Example 15-20 Sample Implementation of the Follow Model

public void follow() {
   System.out.println("Follow method invoked!!!");
   try
   {
   OAViewObjectImpl vo = getCaseList1();
   Row row = vo.getCurrentRow();
   Object id = row.getAttribute("Id");
   System.out.println("Case Id in follow : " + id);
 
   ActivityStreamingService asService = ActivityStreamingServiceFactory
     .getInstance().getActivityStreamingService();
   FollowManager followManager = asService.getFollowManager();
   String serviceID = "oracle.apps.fnd.applcore.crmdemo.model.business.CasesEO";
   String userGUID = ApplSessionUtil.getSession().getUserGuid();
   ActivityActor actor = asService.createActor(userGUID);
   String objectTypeName = "Id";
   ServiceObjectType objectType = asService.findObjectType(serviceID, objectTypeName);
   ActivityObject followedObject = asService.createObject(id.toString(),
                                    objectType, "");
   System.out.println("Calling Follow for Case : " + id);
 
   followedObject.setServiceID(serviceID);
   followManager.followObject(actor, followedObject);
   }
   catch(ActivityException ae) {
     ae.printStackTrace();
     System.out.println("Case follow failed");
   }
}

15.5.7.1 Defining the Service Category

The Follow model is enforced for Activity messages when the category-id of a service contains "business" in its name. A sample service-category-definition and its reference in service-definition are provided in Example 15-21 and Example 15-22.

Note that the ID in the service-category-definition file matches the category-id in the service-definition.xml file and it contains "business".

Example 15-21 Sample service-category-definition.xml File

<service-category-definition xmlns="http://xmlns.oracle.com/webcenter">
 <category id="oracle.apps.fnd.applcore.crmdemo.model.business.CasesEO"
           resourceBundle="oracle.apps.fnd.applcore.crmdemo.BusinessActivityServiceResourceBundle"
           titleKey="CASE_SERVICE_CATEGORY"
           icon="/a/s/g.gif"/>
</service-category-definition>

Example 15-22 Sample service-category-definition Reference

<category-id>oracle.apps.fnd.applcore.crmdemo.model.business.CasesEO</category-id>

15.5.7.2 Adding ActivityTypes for Follow and Unfollow

The Activity types shown in Example 15-23 should be added to the service-definitions of all services that use the Follow model. These Activity types are used to construct the message published when an object belonging to the service is Followed or Unfollowed.

Example 15-23 Adding ActivityTypes for Follow and Unfollow

<activity-type name="followObject"
   displayName="Follow Object"
   messageFormatKey="ACTIVITY_FOLLOW_OBJECT_MSG"
   description="Follow Object">
</activity-type>
 
<activity-type name="unfollowObject"
   displayName="Unfollow Object"
   messageFormatKey="ACTIVITY_UNFOLLOW_OBJECT_MSG"
   description="Unfollow Object">
</activity-type>

15.5.8 How to Render Contextual Actions in Activity Streams

Contextual Actions are rendered for business objects or other resources referenced in Activity Stream messages when contextInfoPopupId is configured in the service-definition.xml file of the business object or resource. The Activity Stream starts an Oracle ADF popup using the popup ID from the service-definition.xml file. The contextInfoPopupId should provide the absolute ID of the popup used for the Contextual Action. A popup with the specified ID should exist in the pages where the Activity Stream is used. This is a requirement for all pages where Contextual Actions-enabled objects are rendered. The Activity Stream will make the serviceId, resourceId, and resourceType properties available to the started popup. The popup should process these parameters and convert them to Contextual Actions-specific parameters and make them available to the Contextual Actions task flow or another component.

This element, which is the direct child of the service-definition element, is used to configure the Contextual Actions popup ID in the service-definition.xml file.

<contextInfoPopupId>:pt1:r1:casePopup</contextInfoPopupId>

The popup sample shown in Example 15-24 uses the serviceId, resourceId, and resourceType properties from the Activity Stream that are made available through the launch variable, and makes them available to the popup.

Example 15-24 Sample Popup for ActivityStream

<af:popup id="casePopup" contentDelivery="lazyUncached"
    eventContext="launcher" launcherVar="source"
    clientComponent="true">
  <af:noteWindow id="nw" >
  <af:panelFormLayout id="pflTst">
  <af:inputText id="itSID"
    label="Service ID"
    value="#{pageFlowScope.serviceId}"
    readOnly="true"/>
  <af:inputText id="itRID"
    label="Resource ID"
    value="#{pageFlowScope.resourceId}"
    readOnly="true"/>
  <af:inputText id="itRType"
    label="Resource Type"
    value="#{pageFlowScope.resourceType}"
    readOnly="true"/>
 </af:panelFormLayout>
</af:noteWindow>
<af:setPropertyListener from="#{source.attributes.serviceId}"
                         to="#{pageFlowScope.serviceId}"
                         type="popupFetch"/>
<af:setPropertyListener from="#{source.attributes.resourceId}"
                         to="#{pageFlowScope.resourceId}"
                         type="popupFetch"/>
<af:setPropertyListener from="#{source.attributes.resourceType}"
                        to="#{pageFlowScope.resourceType}"
                        type="popupFetch"/>
</af:popup>

15.6 Implementing the Oracle Fusion Applications Search Results UI

The Oracle Fusion Applications Search Results UI starts a page using the UI Shell template, that is used to query the Oracle Enterprise Crawl and Search Framework (ECSF).

The minimum requirement is to implement and run a UI Shell template page. A page using the UI Shell template automatically will contain the search components in the Global Area and can be activated when running the page.

Where you have implemented ECSF for your product, you must ensure that you have followed all of the instructions in Chapter 2, "Setting Up Your Development Environment," Chapter 27, "Getting Started with Oracle Enterprise Crawl and Search Framework," and Chapter 28, "Creating Searchable Objects" and in particular:

If you have implemented ECSF and defined the SearchDB connection, the saved searches are saved to the Oracle database and are persisted across sessions.

Data Security Integration

Data security (limiting search results to only those items to which the user has authorized access) is handled by the ECSF.

15.6.1 How to Disable Oracle Fusion Applications Search

There are occasions when you will want to disable Oracle Fusion Applications Search for an application, such as for public (unauthenticated) pages. There are four ways to disable the function:

  • Remove the ECSF libraries (oracle.ecsf shared lib). Oracle Fusion Applications Search will detect the missing dependency and disable itself for all pages in the current user session, even if the user opens a web application that does have the ECSF libraries available.

  • Setup switch using a JVM system property.

    -DFUSION_APPS_SEARCH_ENGINE_AVAILABLE=N
    
  • Use Customization by setting rendered to false on the panelGroupLayout with id "_UISpg6" (the panel containing the Oracle Fusion Applications Search fields) in the UI Shell Main Area. Note that by customizing the fields from the current page, you are not disabling search; the Expression Language bindings on the fields are still evaluated and if the user opens a non-customized page, Oracle Fusion Applications Search will be available.

  • Setting the profile option Fusion Apps Search Enabled to 'N', either at site or user level.

15.6.2 How to Use Basic Search

From the main page of the project in the Global Area, the Categories and Search terms fields are displayed, as shown in Figure 15-23.

Figure 15-23 Basic Search Fields in UI Shell

Basic Search Fields in UI Shell

If you expand the Categories field, a list, similar to that shown in Figure 15-24, is displayed:

Figure 15-24 Search Categories Field Expanded

Search Categories field expanded

Categories

The user can select from the list of Categories and enter a search string. Unchecking the All category unchecks all of the categories. The subset of selected categories will be displayed in the entry area of the dropdown list as a concatenated list separated by a semicolon.

Note:

Categories are not set up at design time by developers. They should be set up either by customers or seeded by teams. Categories are created and stored in ECSF schema, and ECSF provides an API to get a list of categories to the UI for a given user.

Search Term

This is a text field for the values on which to search. The field defaults to showing 20 characters, and can hold a maximum of 2048 characters.

The term is searched for in any of the crawled data, which includes the title, fixed and variable content, attached documents, and tags. So if the search term is foo, the search returns any data containing the word foo.

To find only items with the tag foo, enter ecsf_tags:foo as the search word. No data will be returned if the word foo is in the transactional data but not in the tag.

Click the Play button to initiate the search.

Alternate Word List

Oracle Secure Enterprise Search (SES) will show alternate words to the user when they do a search as suggestions to frequent typos, or better used terms. This list is based on statically defined lists stored in SES.

Oracle Fusion Applications Search uses the ECSF APIs to mimic the SES search and show the alternate words to the user, as shown in Figure 15-25. Clicking the alternate word does a new search using the selected alternate word as the new keywords.

Figure 15-25 Alternate Word Suggestion

Alternate Word Suggestion

Saved Searches

Click the Saved Searches magnifying glass icon to open a list of saved searches. The list shown in Figure 15-26 includes a Personalize… action item that will display the Personalize Saved Searches dialog so that saved searches can be deleted or renamed.

Figure 15-26 Saved Searches List

Saved Searches list
  • Show Results of Last Search: Displays the output of the last search.

  • Personalize: Becomes active if there is a saved search. Click this link to rename or delete a saved search, as shown in Figure 15-27.

    Figure 15-27 Personalized Saved Searches Dialog

    Personalize Saved Searches dialog

    To rename a saved search, select it, enter a new name in the Name field, and click OK.

    To delete a saved search, select it and click Delete.

    Note:

    Entering a name in the Name field without selecting an existing search will create a new Saved Search that uses the last search string seen in the Search window as the search criteria.

15.6.2.1 Search Results

After clicking Search, a modal dialog will display the results of the search. Hovering over the main link will show the last crawled date. Figure 15-28 shows typical results.

Note:

If a search application, such as Finance or HCM, does not respond to the search request within a predetermined period of time, the search results will be displayed but there will be a notice that one or more applications did not respond.

Figure 15-28 Search Results Example

Search results example

To improve performance, the result set size is limited to 10.

The Search Results display consists of:

  • A repetition of the fields displayed in the Global Area.

  • A Filter Tree of Categories: Selected filter values will be applied to the search results. A remove filter icon will appear next to a filter value that has been added. Clicking this icon will remove the filter from the search criteria.

    A category is a group of related objects. Examples include any Oracle Fusion business object, and Oracle WebCenter Portal objects such as wikis and blogs.

    A Searchable Object is the second level. A searchable object is the view object.

    Facets are formed by the Lists of Values defined on an attribute in the Searchable Object. There may be many facets for a Searchable Object, and the facets may be hierarchical, such as is the case in Figure 15-28, where a State facet contains a City facet, which contains a County facet. Only the name of the highest level facet in the hierarchy is shown.

  • A Results section. On the initial query, all selected categories that have a non-zero count will be displayed. That is, if a category has zero results, it will not be displayed. This helps reduce clutter. Only the first category will be expanded. The other categories must be manually expanded.

    Each result found under a category provides a navigation link back to the record.

Result Counts Do Not Add Up

It is possible when viewing the search results, and narrowing your selections using the facet tree, to see counts against the nodes that do not add up. For example, a search on Glasses might return 16. Then if you filter the result by color, you may find Blue (5) and Red (10), which do not add up to 16. This count is the Oracle Secure Enterprise Search (SES) Approximate count based on heuristics, and not an exact count. To make the count exact, start SES and select Global Settings > Query Configuration, and click the Exact count radio button, as shown in Figure 15-29. Note that SES warns against this for performance reasons. See the Oracle Secure Enterprise Search Administration Online Help.

Figure 15-29 Setting the Exact Hit Count in SES

Setting Exact Hit Count in SES

Sort By

This function requires no developer implementation; it is built in.

Users can sort results in the results table. The sort may be done in ascending or descending order, and may be switched using a toggle button.

The sort will be available in two forms, depending on the search parameters:

  • Multiple categories or a single category

    The sort can be based only on Relevance (an implicit universal attribute) and LastModifiedDate (a universal attribute).

  • A Single Searchable Object in a category

    The sort can be based on Relevance, LastModifiedDate, and all other attributes for that Searchable Object, as shown in Figure 15-30.

    Figure 15-30 Sorting on Searchable Object Attributes

    Sorting on Searchable Object Attributes

The Search result will be expanded in the background from the initial 10 results returned with the query, to 100 results returned by a background search started in a separate thread as soon as the 10 results are successfully returned. This is to give a reasonable result to sort. The sort UI will show a spinner and will be disabled until this is finished, and the UI will poll for completion every two seconds and enable those fields. This polling will stop when the background search is complete, or after a fixed number of polls (to stop infinite polling in case of error).

In addition, if there are fewer than 100 results in total, the "About xx Results" header will be replaced with "xx Results", indicating the exact number returned.

The default Sort is Relevance descending, which is the way that records are returned by SES.

The sort is done in memory using a standard Java Collections.sort function, and a comparator that takes into account the date type of the attribute (Date/Number/String) and direction.

Common Filters

The Common Filters panel that is displayed below the Application Filters can be expanded so that it appears similar to Figure 15-31.

Figure 15-31 Common Search Filters

Common Search Filters

The valid values are:

  • Today

    LastModifiedDate equals "todays date."

  • This Week

    LastModifiedDate >= "last Sunday" AND LastModifiedDate <= "this Saturday"

  • This Month

    LastModifiedDate >= "first day of month" AND LastModifiedDate <= "last day of month"

  • This Year

    LastModifiedDate >= "first day of year" AND LastModifiedDate <= "last day of year"

  • Last Year

    LastModifiedDate >= "first day of last year" AND LastModifiedDate <= "last day of last year"

  • Before Last Year

    LastModifiedDate <= "last day 2 years ago"

  • Custom Date Range

    As appropriate for the range. A date picker will be displayed.

Recent Searches

Recent Searches retains the last 10 searches conducted by each user over sessions and makes them available to users to select and run. Keywords entered by the user serve as the name of the recent search, with digits appended for uniqueness, as needed.

Recent Searches is accessed from the Saved Searches dialog by selecting the Recent Searches tab, as shown in Figure 15-32.

Figure 15-32 Selecting the Recent Searches Tab

Selecting the Recent Searches Tab

Clicking any linked portion of the recent search description runs the search and starts the Oracle Fusion Applications Search dialog to display the results.

Recent searches are implemented using the ECSF recent searches feature. See Section 32.5, "Managing Recent Searches."

A recent search is uniquely identified by its filters, such as search term, categories, and facet selections.

A search will be added to the front of the recent search list when performed. If it exists in the list, it will be removed from its current place in the list and added to the front.

15.6.3 How to Implement the GlobalSearchUtil API

A public API is available to call Oracle Fusion Applications Search without requiring the user to use the global search fields at the top of the UI Shell page template.

You can use this API within your UI, such as in a Main Area task flow, and bring up the same UI. You must use the UI Shell.

The API shown in Example 15-25 is available from the oracle.apps.fnd.applcore.globalSearch.ui package in the jdev/oaext/adflib/UIComponents-Viewcontroller.jar file and is the only public API supported by Oracle Fusion Applications Search.

Example 15-25 Oracle Fusion Applications Search API

/**
 * Run a search from a backing bean and have the search results ui component
 * display.
 * @param searchCategories A list of SearchCategory objects to search within.
 * Can be obtained by calling getCategories() from this class.
 * @param searchString The string to search on
 * @param callerContext a String which represents to the caller, the context
 * in which the search result will be called.  This primarily relates to saved
 * searches, which will be saved with this context, and only saved searches
 * with this context shown to the user.
 * @param e The ActionEvent from the page UIComponent that triggered this
 * functionality.
*/
public static void runSearch(List<SearchCategory> searchCategories,
                             String searchString,
                             String callerContext,
                             ActionEvent e)
/**
 * Run a search from a backing bean and have the search results ui component
 * display at a set size.
 * @param searchCategories A list of SearchCategory objects to search within.
 * Can be obtained by calling getCategories() from this class.
 * @param searchString The string to search on
 * @param callerContext a String which represents to the caller, the context
 * in which the search result will be called.  This primarily relates to saved
 * searches, which will be saved with this context, and only saved searches
 * with this context shown to the user.
 * @param e The ActionEvent from the page UIComponent that triggered this
 * functionality.
 * @param popupDimension A Dimension object containing the height and width
 * to display the search results popup.
*/
  public static void runSearch(List<SearchCategory> searchCategories,
                               String searchString,
                               String callerContext,
                               ActionEvent e,
                               Dimension popupDimension)
/**
 * Get a list of all the SearchCategory objects.
 * @return  A List of SearchCategory objects containing all possible search
 * categories.
*/
  public static List<SearchCategory> getCategories();

15.6.3.1 Using the Search API

To use the Search API, create the component and have an actionListener to a backing bean, as shown in Example 15-26. Note that GlobalSearchUtilBean is just an example, not a real bean.

Example 15-26 Creating a Component with actionlistener to Backing Bean

<af:commandButton text="commandButton 1"
          actionListener="#{backingBeanScope.GlobalSearchUtilBean.runSearch}">
</af:commandButton>

From that backing bean, you can call the Oracle Fusion Applications Search API to run the search, as shown in Example 15-27.

Example 15-27 Calling Oracle Fusion Applications Search API to Run Search

public class GlobalSearchUtilBean {
    public GlobalSearchUtilBean()
    {
    }
    public void runSearch(ActionEvent actionEvent)
    {
      List<SearchCategory> categories =GlobalSearchUtil.getCategories();
      // manipulate search category list here
      String searchString = "some search string";
      GlobalSearchUtil.runSearch(categories, searchString, actionEvent);
    }
}

15.6.3.2 Running the Oracle Fusion Applications Search UI Under Oracle WebLogic Server

For details of running the ECSF artifacts, such as the SearchFeedServlet, see Chapter 28, "Creating Searchable Objects."

To run the UI Shell and Oracle Fusion Applications Search, follow the setup instructions for running Applications Core under Oracle WebLogic Server in Chapter 2, "Setting Up Your Development Environment" and the instructions on how to set up a UI Shell page, menu entries and task flows from Section 14.1, "Introduction to Implementing the UI Shell". This should give you a running UI Shell project.

Add the SearchDB database connection to the project. For more information about creating the SearchDB connection, see Section 32.6.1, "How to Create the SearchDB Connection on Oracle WebLogic Server Instance".

15.6.4 Introduction to the Crawled Objects Project

The Crawled Objects Project lets you crawl your Search view objects in Oracle WebLogic Server, and set up Oracle Fusion Applications Search to use those crawled view objects.

The business component objects you will create (specifically the Searchable view object) will contain references to the Oracle Fusion Middleware Extensions for Applications base classes.

Update the ECSF command-line script (runCmdLinScript.sh) to reference the JAR files containing the base classes. Example 15-28 shows the UNIX version; the DOS version is similar.

Example 15-28 Updating ECSF Command-Line Script to Reference Applications Core JAR Files

export APPLCORE_CP=${ORACLE_HOME}/jdeveloper/jdev/oaext/adflib/Common-Model.jar:${ORACLE_HOME}/jdeveloper/jdev/oaext/adflib/Tags-Model.jar
export ADMIN_CLASS=oracle.ecsf.cmdlineadmin.CmdLineAdmin
 
${JAVA_HOME}/java -cp ${ADMIN_CP}:${APPLCORE_CP} ${ADMIN_CLASS} ${CONNECT_INFO}

15.6.5 How to Implement Tags in Oracle Fusion Applications Search

A view object is available to reference Oracle WebCenter Portal Tags. This view object is available in the ORACLE_HOME/jdeveloper/jdev/oaext/adflib/Tags-Model.jar library JAR file.

You may use this view object using a view link and a predefined Search extension to enable the crawling of Oracle WebCenter Portal Tags, both in initial and incremental (someone has updated the tags) crawls.

Follow these steps:

  1. Create your Searchable view object as usual. Example 15-29 uses a Searchable view object over FND_LOOKUPS_VL in the query.

    Example 15-29 Creating a Searchable View Object

    SELECT LOOKUP_TYPE,
           VIEW_APPLICATION_ID,
           LANGUAGE,
           SOURCE_LANG,
           MEANING,
           DESCRIPTION,
           CREATED_BY,
           CREATION_DATE,
           LAST_UPDATED_BY,
           LAST_UPDATE_DATE,
           LAST_UPDATE_LOGIN,
           'oracle.apps.fnd.applcore.lookuptype' AS SERVICE_ID,
           lookup_type||'.'||to_char(view_application_id)||'.'||language||'.'||meaning as RESOURCE_ID
    FROM FND_LOOKUP_TYPES_TL
    

    The SERVICE_ID specifically identifies your Searchable view object.

    The RESOURCE_ID identifies the specific row for the SERVICE_ID. It is a dot-separated primary key of the entity.

    These two values will be used when setting up tags in your regular UI and must match. For example, if you have a page with a form and a tag button, the Oracle WebCenter Portal tag would be set up as shown in Example 15-30.

    Example 15-30 Setting up the Oracle WebCenter Portal Tag

    <af:panelFormLayout id="pfl1">
       <tag:taggingButton serviceId="oracle.apps.fnd.applcore.lookuptype"
                   resourceName="#{bindings.Description.inputValue}"
                   resourceId="#{bindings.LookupType.inputValue}.#{bindings.ViewApplicationId.inputValue}.#{bindings.Language.inputValue}.#{bindings.Meaning.inputValue}"/>
       <af:region value="#{bindings.tagginglaunchdialog1.regionModel}"
                           id="r1"/>
       <af:panelLabelAndMessage label="#{bindings.LookupType.hints.label}"
                                       id="plam4">
         <af:outputText value="#{bindings.LookupType.inputValue}" id="ot9"/>
    </af:panelLabelAndMessage>
    

    See Section 15.1, "Implementing Tagging Integration" for setting up tags in your UI. Figure 15-33 shows the attributes for lookup types.

    Note:

    Do not forget to mark your key columns and ensure the order is consistent between the view object and the tag:taggingButton.resourceId attribute.

    Figure 15-33 Tags - Searchable View Object Lookup Types

    Tags - SVO Lookup types

    Figure 15-34 shows the attributes for Searchable view object lookup types.

    Figure 15-34 Tags - Lookup Types

    Tags - Lookup types.
  2. Add a view link to the TagSVO (service view object) linking the Search view object and the Applications Core Tag view object.

    The view link should look similar to Figure 15-35.

    Figure 15-35 View Link Example

    View link example
  3. Update the Body field to include the tags of the child view object in the relevant position in the string as defined by your management.

    This will be an expression of the form <accessor Name>.Tag, such as tagSVO.Tag.

How to Do an Incremental Crawl

To do an incremental crawl:

  1. Update the Searchable View Object Search Plugin field (see Figure 15-35, "View Link Example") to "oracle.apps.fnd.applcore.search.TagSearchPlugin", or as shown in Example 15-31, create a subclass so that you can incorporate your security rules.

    Example 15-31 Creating a Subclass

    package oracle.apps.fnd;
    import oracle.apps.fnd.applcore.search.TagSearchPlugin;
    public class WlsTestTagSearchPlugin
    extends TagSearchPlugin
    {
      // All implementation through super class, or override methods important to you.
      // Be careful if implementing
      //  public Iterator getChangeList(SearchContext ctx, String changeType)
      // to call super(ctx, changeType) to get the applcore functionality.
    }
    

    Ensure you add a parameter passing the service ID of the Search view object. This may be done by clicking the LOV symbol next to the Search Plugin field, shown in Figure 15-34. See Figure 15-36.

    Figure 15-36 Search Plugin

    Search Plugin example

    There are two parameters, shown in Table 15-7, that may be passed to the extension.

    Table 15-7 Parameters that can be passed to the plug-in

    Parameter Required Description

    TAG_SERVICE_ID

    Yes

    Service ID of the Searchable view object. This value must match the value in the tag:taggingButton component and the service_id of the Searchable view object query.

    KEY_SPLITTER_CLASS

    No

    An optional class that extends oracle.apps.fnd.applcore.search.BaseKeySplitter.

    This is a strategy class for splitting the resourceId value into individual primary key attribute values. By default, oracle.apps.fnd.applcore.search.DefaultKeySplitter is used, which will split values based on a period separator (the applications standard). The separated PS attribute values are matched to the primary key columns in the order the primary key columns are defined in the view object flat table editor.

    For more flexible arrangements, teams can implement any scheme they want (such as name-value pairs) by creating their own key splitter class and setting this parameter.


  2. Start the SearchFeedServlet in the user interface project.

You now can crawl using the command-line script. A full crawl will be done first, then on subsequent crawls the incremental functionality will call the getChangeList() method.

15.6.6 How to Use the Actionable Results API with Oracle Fusion Applications Search

This section details how to set up ECSF searchable objects to use with Oracle Fusion Applications Search. For information about setting up your global search infrastructure, see Chapter 27, "Getting Started with Oracle Enterprise Crawl and Search Framework."

Figure 15-37 shows the result that will be produced (a single row in the search results table).

Figure 15-37 Search Results Example

Search results example

The terminology referred to in this result is:

  • Flat Table URL Action is the Action Link.

  • Title for Flat Table 1:Col1619:Col2619 is the Fixed Content.

  • Any other required information would be added later is the Variable Content.

  • Task Action 1 is Other Actions.

As shown in Figure 15-38, ECSF searchable objects support two distinct Action Types: URL and Task. See also Figure 15-39 and Figure 15-40.

Most Oracle Fusion Applications will use the Task type with specific named parameters to integrate with the UI Shell; however both types will work.

Figure 15-38 Search Properties Example

Search properties example

Fixed Content

The Fixed Content is derived from the Search Properties Title field.

Variable Content

The Variable Content is derived from the Search Properties Body field.

15.6.6.1 Implementing the URL Action Type

Figure 15-39 shows a URL Action.

Figure 15-39 Search Result Actions - URL Action

Search Result Actions - URL Action

For URL Action Types, the Oracle Fusion Applications Search will open a new browser tab or window containing the URL. To configure this type, add a URL Search Result Action with these parameters.

  • A unique name

  • Action Type of URL

  • An Action Target to the required destination, including groovy substitution parameters

  • A Title

No Parameters are required; however a single iconURL parameter may be defined if an icon is required for the URL action. See Table 15-8.

Table 15-8 iconURL Parameter

Name Required Description

iconURL

No

URL of icon to show next to the Action. Can be a relative reference such as /media/search/mime_doc.gif or a full URL such as http://host:port/path/to/icon.gif.


The icon will be shown in the search results with the title given in the Title field. When clicked, a new browser tab or window will open with this URL.

15.6.6.2 Implementing the Task Action Type

Figure 15-40 shows a Task Action.

Figure 15-40 Search Result Actions - Task Action

Search Result Actions - Task Action

For Action Types of Task, the Oracle Fusion Applications Search will open a UI Shell tab in the current page, or a new page containing the task flow. To configure this type, add a Task Search Result Action with these parameters.

  • A unique name

  • Action Type of Task

  • A Title

Parameters are shown in Table 15-9. Note that, although this table resembles Table 15-10, it presents the use case that the majority of users will use. The information in Table 15-10 is for a very small use case.

The action will be shown in the search results with the title given in the Title field. When clicked, a new UI Shell tab window will open with this task flow. If the viewId parameter is for the current page, the UI Shell tab will be in the current page; otherwise the current page will be replaced with a new UI Shell page with the search result.

Note:

Do not enter double quotation marks around the groovy expressions; use single quotation marks instead.

Table 15-9 Task Action Type Parameters

Name Required Description

viewId

Y

Name of the page. This is shown in the browser URL bar. For example, in http://127.0.0.1:8989/context-root/faces/TestUIShellPage, it would be /TestUIShellPage (Note the leading slash).

pageParametersList

N

Parameters list for the page. This is a semicolon delimited String of name-value pairs. For example, "param1=value1;param2=value2"

taskFile

Y

Name of the task definition file. For example, /WEB-INF/task-flow-definition.xml. See Section 15.6.6.3, "Passing Parameters in Oracle Fusion Applications Search".

taskName

Y

The task flow definition ID. Available from the task definition file <task-flow-definition> ID attribute. For example, <task-flow-definition id='task-flow-definition'> would be "task-flow-definition". See Section 15.6.6.3, "Passing Parameters in Oracle Fusion Applications Search".

navTaskKeyList

N

Key list to pass into the task flow to open in the target workspace. This is a semicolon delimited string of keys or key-value pairs. For example "key1;key2=value2"

navTaskParametersList

N

Parameters list to pass in to the task flow to open in the target workspace. This is a semicolon delimited string of name-value pairs. For example "param1=value1;param2=value2"

iconURL

N

URL of an icon to show next to the Action. Can be a relative reference such as /media/search/mime_doc.gif or a full URL such as http://host:port/path/to/icon.gif.

toolTip

N

Tooltip of the action. This also is available for URL actions.

navTaskLabel

N

Label to show on the results tab. Set the tab title of the tab that is opened after clicking a search result action. If not set, it will use the Action Name (the value shown in the results).

webApp

Y

Attribute used to look up the host and port of the associated WorkArea or Dashboard from the ASK deployment tables. These tables are populated at deployment time through Functional Setup tasks.


Caution:

If you have a searchable view object with a task search action, the parameters passed to the task flow from FndUIShellController.navigate(...) will be Strings, not the native type of the view object attributes. You must ensure that these values are converted from their native type to a String (in the navTaskParametersList) and back correctly (in your task flow).

For Integer types, this is largely automatic (as long as you reference the parameter as a String in the task flow), but use caution for dates and decimals.

15.6.6.2.1 How to Implement Preferred Navigation

Oracle Fusion Applications Search supports two parameters, applicationStripe and pageDefinitionName, in task search actions that, if they are present, change the definition of the other task action parameters used for navigation. These parameters all become "caret delimited." That is, instead of having one value per parameter, they have multiple values, and they are delimited by the caret "^" character. In this case, all parameters must have the same number of delimited parts.

This additional configuration allows you as the developer to set up different navigation targets for the same action. The actual target followed will be determined when the user clicks the result and will be based on a permissions check based on the applicationStripe and pageDefinitionName parameters. If these two parameters are not supplied, the other parameters will be used "as is," and navigation will be performed based on their values.

If the applicationStripe and pageDefinitionName parameter values are supplied, the algorithm used is the same as for tagging.

  • Divide all delimited parameters based at the caret, and produce an ordered list of targets that can be opened.

  • If there is only one target defined, use it with no permission check.

  • For each target, determine if the user can open the page and task flow.

  • If a target that can be opened is in the current view, use it.

  • Take the first target that can be opened.

Whatever the outcome of the permissions check, you must ensure that at least one target can be opened, otherwise users will be presented with a blank page when they click the search result.

The parameters and descriptions for Preferred Navigation are shown in Table 15-10. Note that, although this table resembles Table 15-9, it presents a more complicated use case in which developers want to do a security check and direct the user to the most secure end point (the first allowed one in the list). The meaning of these columns changes with the caret delimitation; that is, a caret-delimited list of the old values, as well as two new parameters. Most users need to use only the information in Table 15-9.

Table 15-10 Parameters for Preferred Navigation

Name Required Delimited by caret "^" Description

applicationStripe

N

Y

(This attribute is used for pages.) Check security of the page against the policies that are located in LDAP. The applicationStripe name must be the same as the stripe name of the LDAP policy store, which is the same as the web.xml application.name attribute. If this parameter is supplied, the pageDefinitionName parameter must be supplied also. Example: crm^hcm

pageDefinitionName

N

Y

A delimited string of page definition names. If this parameter is supplied, the applicationStripe parameter also must be supplied. Example: oracle.apps.view.pageDefs.Test1PageDef^oracle.apps.view.pageDefs.AnotherPageDef

viewId

Y

Y

Name of the page for the pillar. This is shown in the browser URL bar. For example, in http://127.0.0.1:8989/context-root/faces/TestUIShellPage, it would be "TestUIShellPage^AnotherUIShellPage".

webApp

Y

Y

Attribute used to look up the host and port of the associated Work Area or Dashboard from the ASK deployment tables. These tables are populated at deployment time through Functional Setup tasks.

pageParametersList

N

Y

Parameters list for the page. This is a semicolon delimited string of name-value pairs. For example, "param1=value1;param2=value2^anotherParam1=value1;anotherParam2=value2"

taskFile

Y

Y

Name of the task definition file. For example, "/WEB-INF/task-flow-definition.xml^/WEB-INF/anothertask-flow-definition.xml". See Section 15.6.6.3, "Passing Parameters in Oracle Fusion Applications Search".

taskName

Y

Y

The task flow definition ID that is available from the task definition file <task-flow-definition> id attribute. For example, <task-flow-definition id='task-flow-definition'> would be "task-flow-definition^another-task-flow-definition". See Section 15.6.6.3, "Passing Parameters in Oracle Fusion Applications Search".

navTaskKeyList

N

Y

Key list to pass into the task flow to open in the target workspace. This is a semicolon delimited string of keys or key-value pairs. For example "key1;key2=value2^anotherKey1;anotherKey2=value2"

navTaskParametersList

N

Y

Parameters list to pass in to the task flow to open in the target workspace. This is a semicolon delimited string of name-value pairs. For example "param1=value1;param2=value2^anotherParam1=value1;anotherParam2=value2"

navTaskLabel

N

Y

The label to show on the results tab. (Set the tab title of the tab that is opened after clicking a search result action.) If not set, it will use the Action Name (the value shown in the results). For example: "Manage user^View User" (Note: This will be shown on the UI, so use resource bundles.)

iconURL

N

N

The URL of the icon to show next to the Action.It can be a relative reference, such as /media/search/mime_doc.gif or a full URL, such as http://host:port/path/to/icon.gif.

Tooltip

N

N

A tooltip of action. This also is available for URL actions.


15.6.6.3 Passing Parameters in Oracle Fusion Applications Search

Ordinarily, taskFlowID uses the format <path><name>.xml#<name>; for instance taskFlowID="/WEB-INF/CaseDetails.xml#CaseDetails". However, Oracle Fusion Applications Search has taskFile and taskName attributes as shown in Figure 15-40. The code will merge them, adding the "#," so they become <taskFile>#<taskName>.

Parameters always are passed as parameter name=value. Often, it is either a literal value or an expression such as #{pageFlowScope.val}. Example 15-32 shows how to pass four parameters.

Example 15-32 Parameter Passing in Oracle Fusion Applications Search

<SearchResultActions>
  <Action
    Name="View Lookup Type"
    ActionType="Task"
    DefaultAction="true">
    <Title>
      <![CDATA["Lookup: " + Meaning]]>
    </Title>
    <ActionTarget>
      <![CDATA[null]]>
    </ActionTarget>
    <Parameters>
      <Parameter Name="navTaskParametersList">
        <Value>
          <![CDATA["lookupType=" + LookupType + ";viewApplicationId=" + ViewApplicationId + ";language=US;meaning=" + Meaning]]>
        </Value>
      </Parameter>
      <Parameter Name="webApp">
        <Value>
          <![CDATA['GlobalSearch']]>
        </Value>
      </Parameter>
      <Parameter Name="TaskFile">
        <Value>
          <![CDATA["/WEB-INF/LookupTypeSearchResultsTaskFlow.xml"]]>
        </Value>
      </Parameter>
      <Parameter Name="navTaskKeyList">
        <Value>
          <![CDATA["meaning=" + Meaning]]>
        </Value>
      </Parameter>
      <Parameter Name="TaskName">
        <Value>
          <![CDATA["LookupTypeSearchResultsTaskFlow"]]>
        </Value>
      </Parameter>
      <Parameter Name="viewId">
        <Value>
          <![CDATA["TestUIShellPage"]]>
        </Value>
      </Parameter>
    </Parameters>
  </Action>

15.6.6.4 Ordering the Other Actions

In the ECSF search UI in JDeveloper, it is possible to define no action, or a single default action.

If a default action is defined, it will be used. The other actions will be shown in sorted order based on task title. If no default action is defined, the first sorted action will be used as the default action.

This sorting mechanism is used because there is no way, using the current ECSF APIs, to provide a stable order of actions.

Due to this sorting mechanism, it is strongly recommended to have stable, sortable task titles (they may be groovy bound and therefore mutate based on an individual search result) to prevent confusing the end user.

15.6.6.5 Using Click Path and the Saved Search

When the user is using Oracle Fusion Applications Search prior to saving a search, he or she may perform a number of interactions with the UI including:

  • Expanding the attribute filters by selection (performs searches)

  • Narrowing the search terms

  • Opening unsearched groups (which performs searches in those groups)

  • Scrolling through results in a group

This is called the click path of the user.

When a search is saved, some of this information (the structural part at the tip of the click path) is saved, but prior actions and exact scroll positions are not. This means that when running a saved search, the following items are not restored to the user:

  • Exact expanded groups in the result at the time of save

  • Scroll positions within a group

  • Full LOV expansion state of attribute filters

When ECSF returns facet information, it returns facet entries only for the level below that which is selected. For example, if there are no filters, the facets will be shown correctly with one level of detail. If a first-level facet is selected, that selection will be shown, but not its siblings. If there are facets below that level, this next level will be shown as these are returned. As the user starts to refine or expand the attribute filters, the search filters will be filled in based on this new click path.

15.6.7 How to Integrate Non-Applications Data into Oracle Fusion Applications Search

Oracle Fusion Applications Search can also be used with non-standard ECSF searchable view objects.

15.6.7.1 Oracle Business Intelligence Integration

Oracle Business Intelligence results will be shown in a results area separate from Oracle Fusion Applications Search view object results. To implement this separation, Oracle Fusion Applications Search shows results in a multiple-tab format.

The tabs are named Applications, where all Search view objects and WebCenter Portal results will reside, as well as Business Intelligence. The split is performed at a category (or searchable groups) level, so you will see a consolidated list of categories in the multi-select category dropdown. These categories are split at search time.

The business rule that splits categories into the Oracle Business Intelligence table is a lowercase category_name, such as bi_%.

Although the formatting of Oracle Business Intelligence results will be slightly different, no developer action is required.

Oracle Secure Enterprise Search (SES) Setup

To set up SES, you need to set up these parameters:

  • Source

    See the Oracle Fusion Middleware Developer's Guide for Oracle Business Intelligence Enterprise Edition for how to create your Oracle Business Intelligence source. Define a source based on the Oracle EBusiness Suite R12, and give the following parameters:

    SES Source Configuration:
    Configuration URL: http://10.156.30.40:9704/bisearch/crawler/oracle.biee.search.BISearchableTreeObject/ConfigFeed?forceInitialCrawl=true
    User ID: Administrator
    Password: Admin123
     
    Authorization Tab:
    HTTP endpoint for authorization: http://10.156.30.40:9704/bisearch/crawler/SecurityService
    User ID: Administrator
    Password: Admin123
    Business Component: oracle.biee.search.BISearchableTreeObject
    Display URL Prefix: http://10.156.30.40:9704/bisearch/urlbuilder
     
    where the IP address is your Oracle Business Intelligence server installation, and the user name/password are for a sufficiently authorized Oracle Business Intelligence user.
     
    Leave all other values at default.
    
  • Source Group

    Create a source group (SES Searchtab then Source groups) and name it bi_<some code name>.

    It must start with bi_ so Oracle Fusion Applications Search can recognize it as an Oracle Business Intelligence category.

    You may go into Global Settings and translate the group name so the users see a more recognizable name.

    Import the group as an external category into ECSF. See "Importing Source Group into ECSF".

  • Searching

    When Searching, the Oracle Business Intelligence results will be displayed in a separate tab, as shown in Figure 15-41.

    Figure 15-41 Oracle Business Intelligence Search Results in New Tab

    BI Search Results in New Tab

    If there are only Oracle Business Intelligence, or only Oracle Fusion Applications or WebCenter Portal categories selected, only the one tab appropriate to those categories is displayed. Otherwise, you can search both and tab between the results.

    When you click a link, you will be redirected to Oracle Business Intelligence. If you do not have a consolidated Oracle Internet Directory (OID) setup, you will be asked to log in again.

15.6.7.2 Integrating Oracle WebCenter Portal

To set up and crawl an Oracle WebCenter Portal environment, see the "Configuring Search Parameters and Crawlers Using Fusion Middleware Control" section in the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter Portal and then import the searchable objects into ECSF as external categories.

Importing Source Group into ECSF

The group now should be searchable from within the SES Search UI.

To allow the group to be searchable from Oracle Fusion Applications Search, it must be imported using the cmdLineAdmin tool or Oracle Enterprise Manager Fusion Middleware Control. Follow these steps if you use the tool:

  1. Start the cmdLineAdmin tool. Its prompt will be displayed.

  2. Issue this command at the prompt:

    > manage instance 124 (where 124 differs for each developer).

    The prompt will change to show that an instance is being managed.

  3. Enter this command:

    Instance: 124> list external categories

    This information is displayed:

    List of External Categories for Instance with ID 124:
    ---------------------------------------------------
    ID               | Name                           |
    ---------------------------------------------------
    100000000013878  | bi_SearchableTreeDirectory     |
    100000000013879  | WebCenter                      |
    
  4. Enter this command:

    Instance: 124> import external categories

    This command should return an Import successful message.

  5. Enter this command:

    Instance: 124> list external categories

    This information is displayed:

    List of External Categories for Instance with ID 124:
    List of External Categories for Instance with ID 124:
    ---------------------------------------------------
    ID               | Name                           |
    ---------------------------------------------------
    100000000014896  | bi_SearchableTreeDirectory     |
    100000000014897  | WebCenter Jive Forums          |
    100000000014898  | WebCenter Jive Announcements   |
    100000000014899  | WebCenter                      |
    

15.6.7.3 Ensuring Parity of Users

Users must be defined in multiple applications if you do not have a single authentication store.

Ensure that you have a user defined that is common across both Oracle Fusion Applications and Oracle WebCenter Portal.

For instance, you can create an fmwadmin user on the Oracle Fusion Applications side by adding to the jazn-data.xml file.

With Oracle Secure Enterprise Search (SES) Authentication pointing to the ECSF SearchFeedServlet, which is using the WebLogic Server container security, this user will be verified by the SES authentication callbacks.

In a true enterprise environment, both the Oracle Fusion Applications web container and WebCenter Portal would be set up with the same OID.

Using two different authentication stores will mean you get multiple logins when clicking results.