6 Create Custom Data Action Plug-ins

You can create custom data action plug-ins to use in Oracle Analytics Cloud.

Data action plug-ins extend Oracle Analytics Cloud and enable users to select data-points in visualizations and to invoke specific actions. Oracle Analytics Cloud provides a core set of data actions that cover many common use cases, but by writing your own data action plug-in, you can extend this functionality even further.

The tutorial uses an example to help you understand how to create a custom data action plug-in.

Tutorial iconTutorial

You must have a basic understanding of the following to create custom data action plug-ins:

  • JavaScript
  • RequireJS
  • JQuery
  • KnockoutJS

About Data Action Plug-ins and the Data Actions Framework

Data action plug-ins leverage the data actions framework to provide custom, data-driven actions that are tightly integrated into the Oracle Analytics Cloud user interface.

When a user invokes a data action, the Data Action Manager passes the request context (for example, qualified data reference, measure values, filters and metadata) to the data action plug-in which is responsible for handling the request. Oracle provides four types of data action plug-ins: CanvasDataAction, URLNavigationDataAction, HTTPAPIDataAction and EventDataAction. You can extend these data action plug-in types along with their abstract base classes to provide your own data actions.

Data Action Categories

The data action categories include Navigate to URL, HTTP API, Navigate to Canvas, and Event actions:

  • Navigate to URL: Opens the specified URL in a new browser tab.
  • HTTP API: Uses the GET/POST/PUT/DELETE/TRACE commands to target an HTTP API and doesn't result in a new tab. Instead the HTTP status code is examined and a transient success or failure message is displayed.
  • Navigate to Canvas: Enables the user to navigate from a source canvas to a target canvas in either the same or a different visualization. Any filters that are in effect in the source canvas are passed to the target canvas as external filters. When the target canvas opens, it attempts to apply the external filters to the visualization. The mechanism by which external filters are applied isn't described here.
  • Event Actions: Publishes an event using the Oracle Analytics Cloud event router. Any JavaScript code (for example, a third-party plug-in) can subscribe to these events and handle their custom response accordingly. This provides the maximum flexibility because the plug-in developer can choose how the data action responds. For example, they can choose to display a user interface or pass data to multiple services at once.

Both the Navigate to URL and HTTP API data action category types can use a token syntax to inject data or metadata from the visualization into the URL and POST parameters.

URL Token Replacement

HTTP data actions can replace tokens in URLs with values from the context passed to the data action. For example, qualified data reference values, filter values, username, project path, and canvas name.

Token Notes Replace With Example Result
${valuesForColumn:COLUMN} NA Column display values from the qualified data reference. ${valuesForColumn: "Sales"."Products"."Brand"} BizTech,FunPod
${valuesForColumn:COLUMN, separator:"/"} Any token that can potentially be replaced with multiple values supports the optional separator option. The separator defaults to a comma (,) but you can set it to any string. You can escape double quotes inside this string by using a backslash (\). Column display values from the qualified data reference. ${valuesForColumn: "Sales"."Products"."Brand"} BizTech,FunPod
${valuesForColumn:COLUMN, separationStyle:individual} Any separationStyle defaults to delimited but you can set it to individual if the user needs to generate separate URL parameters for each value. Column display values from the qualified data reference. &myParam=${valuesForColumn: "Sales"."Products"."Brand"} &myParam=BizTech&myParam=FunPod
${keyValuesForColumn:COLUMN} NA Column key values from the qualified data reference. ${keyValuesForColumn:COLUMN} 10001,10002
${env:ENV_VAR} Supported environment variables are: sProjectPath, sProjectName, sCanvasName, sUserID, and sUserName. An environment variable. ${env:sUserID} myUserName

Data Action Context

You can define a context that is passed when the user invokes a data action.

You define how much of the context is passed to the data action when you create the data action.

Qualified Data Reference

When the data action is invoked a qualified data reference is generated for each marked data point using an array of LogicaFilterTree objects. A LogicalFilterTree consists of multiple LogicalFilterNode objects arranged in a tree structure. This object includes:

  • The attributes on the row or column edges of the data layout.
  • The specific measure on the measure edge that addresses each marked cell.
  • The specific measure value for each marked cell.
  • Key values and display values.

Environment Variables

In addition to the data and metadata describing each marked data point, certain data actions may need further context describing the environment from where the data action is invoked. Such environment variables include:

  • User ID
  • User Name
  • Project Path
  • Canvas Name
  • Is Desktop Mode
  • Is Embedded Mode

Data Action Code Design

You create data actions using API classes.

  • There are four concrete classes of data action that inherit from the AbstractDataAction class:
    • CanvasDataAction
    • URLNavigationDataAction
    • HTTPAPIDataAction
    • EventDataAction
  • You can create new types of data actions using the data action plug-in API. See Data Visualizer SDK Reference.
  • The registry of data action types is managed by the DataActionPluginHandler.
  • Code that creates, reads, edits, deletes, or invokes instances of data actions does so by publishing events.
  • Events are handled by the DataActionManager.

Data Action Model Classes

There are several different types of data action model classes.

AbstractDataAction

This class is responsible for:

  • Storing the Knockout Model (subclasses are free to extend this with their own properties).
  • Defining the abstract methods that subclasses must implement:
    • + invoke(oActionContext: ActionContext, oDataActionContext:DataActionContext) <<abstract>>

      Invokes the data action with the passed context - should only be called by the DataActionManager.

    • + getGadgetInfos(oReport): AbstractGadgetInfo[] <<abstract>>

      Constructs and returns the GadgetInfos responsible for rendering the user interface fields for editing this type of data action.

    • + validate() : DataActionError

      Validates the data action and returns null if valid or a DataActionError if it's invalid.

  • Providing the default implementation for the following methods used to render generic parts of the data action user interface fields:
    • + getSettings():JSON

      Serializes the data action's Knockout Model to JSON ready to be included in the report (uses komapping.toJS(_koModel)).

    • + createNameGadgetInfo(oReport) : AbstractGadgetInfo

      Constructs and returns the GadgetInfo that can render the data action's Name field.

    • + createAnchorToGadgetInfo(oReport) : AbstractGadgetInfo

      Constructs and returns the GadgetInfo that can render the data action's Anchor To field.

    • + createPassValuesGadgetInfo(oReport) : AbstractGadgetInfo

      Constructs and returns the GadgetInfo that can render the data action's Pass Values field.

Subclasses may not need all of the GadgetInfos that the base class provides so they may not need to call all of these methods. By separating out the rendering of each field in this way, subclasses are free to pick and choose the gadgets they need. Some subclasses may even choose to provide a different implementation of these common data action gadgets.

CanvasDataAction, URLNavigationDataAction, HTTPAPIDataAction, EventDataAction

These are the concrete classes for the basic types of data actions. These classes work by themselves to provide the generic user interface for these types of data action. They can also act as convenient base classes for custom data action plug-ins to extend.

  • CanvasDataAction: Used to navigate to a canvas.
  • URLNavigationDataAction: Used to open a web page in a new browser window.
  • HTTPAPIDataAction: Used to make a GET/POST/PUT/DELETE/TRACE request to an HTTP API and handle the HTTP Response programatically.
  • EventDataAction: Used to publish JavaScript events through the Event Router.

Each class is responsible for:

  • Implementing the abstract methods from the base class.
    • invoke(oActionContext: ActionContext, oDataActionContext:DataActionContext)

      This method should invoke the data action by combining the properties defined in the KOModel with the specified DataActionContext object.

    • getGadgetInfos(oReport): AbstractGadgetInfo[]

      This method should:

      • Create an array containing AbstractGadgetInfos.
      • Call individual createXXXGadgetInfo() methods pushing each AbstractGadgetInfo into the array.
      • Return the array.
  • Providing the additional methods for creating the individual gadgets that are specific to the particular subclass of data action.

Subclasses of these concrete classes may not need to use all of the gadgets provided by their superclasses in their custom user interfaces. By separating out the construction of each gadget in this way, subclasses are free to pick and choose the gadgets they need.

DataActionKOModel, ValuePassingMode

The DataActionKOModel class provides the base KOModel shared by the different subclasses of AbstractDataAction. See DataActionKOModel Class.

Data Action Service Classes

There are several different data action service classes.

DataActionManager

DataActionManager class diagram

All communication with DataActionManager uses ClientEvents.DataActionManager which implements event handlers for:

  • Managing the set of data actions defined in the current project.
  • Invoking a data action.
  • Retrieving all the data actions defined in the current project.
  • Retrieving all the data actions that are applicable to the current marked data points.

DataActionContext, EnvironmentContext

When a data action is invoked, the DataActionContext class contains the context that's passed to the target.

  • getColumnValueMap()

    Returns a map of attribute column values keyed by attribute column names. These define the qualified data reference for the data points that the data action is invoked from.

  • getLogicalFilterTrees()

    Returns a LogicalFilterTrees object describing the qualified data references for the specific data points that the data action is invoked from (see the InteractionService for details).

  • getEnvironmentContext()

    An instance of the EnvironmentContext class describing the source environment such as:

    • getProjectPath()
    • getCanvasName()
    • getUserID()
    • getUserName()
  • getReport()

    Returns the report that the data action is invoked from.

DataActionHandler

The DataActionHandler class registers the various data action plug-ins. Its API is broadly consistent with the other plug-in handlers (for example, VisualizationHandler).

The DataActionHandler class provides the following public methods:

  • getClassName(sPluginType:String) : String

    Returns the fully qualified class name for the specified data action type.

  • getDisplayName(sPluginType:String) : String

    Returns the translated display name for the specified data action type.

  • getOrder(sPluginType:String) : Number

    Returns a number used to sort lists of the types of data action into the preferred order.

The DataActionHandler class provides the following static methods:

  • getDependencies(oPluginRegistry:Object) : Object.<String, Array>

    Returns a dependency map covering all the registered data action types.

  • getHandler(oPluginRegistry:Object, sExtensionPointName:String, oConfig:Object) : DataActionPluginHandler

    Constructs and returns a new instance of the DataActionHandler class.

DataActionUpgradeHandler

The DataActionUpgradeHandler class is called by the UpgradeService when a report is opened.

The DataActionHandler class provides two main methods:

  • deferredNeedsUpgrade(sCurrentVersion, sUpgradeTopic, oDataActionJS, oActionContext) : Promise

    Returns a Promise that resolves to a Boolean indicating whether the specified data action must be upgraded (true) or not (false). The method decides whether the data action must be upgraded by comparing the version number of the data action instance with the version number obtained from the data action's constructor. If the instance's version number is less than the constructor's version number, the data action instance must be upgraded.

  • performUpgrade(sCurrentVersion, sUpgradeTopic, oDataActionJS, oActionContext, oUpgradeContext) : Promise

    Carries out the upgrade on the specified data action and resolves the Promise. The upgrade itself is carried out by calling the upgrade() method on the data action (only the specific subclass of data action being upgraded is qualified to upgrade itself).

  • getOrder(sPluginType:String) : Number

    Returns a number used to sort lists of the types of data action into the preferred order.

Data Action Code Interactions

A data action interacts with Oracle Analytics Cloud code when it creates a user interface field, and when a user invokes a data action.

Create the Field for a New Data Action Instance

This interaction starts when Oracle Analytics Cloud wants to render a data action user interface field. To do so, it:

  1. Creates a PanelGadgetInfo that acts as the parent GadgetInfo for the GadgetInfos that the data action returns.
  2. Calls getGadgetInfos() on the data action.
  3. Adds the data action's GadgetInfos as children of the PanelGadgetInfo created in the first step.
  4. Creates the PanelGadgetView that renders the PanelGadgetInfo.
  5. Sets the HTMLElement that's the container of the PanelGadgetView.
  6. Registers the PanelGadgetView as a child HostedComponent of a HostedComponent that's already attached to the HostedComponent tree.

    This renders the data action's gadgets inside the Panel gadget in the order they appear in the array returned by getGadgetInfos().

Invoke a Data Action

This interaction starts when the user invokes a data action through the Oracle Analytics Cloud user interface (for example, from the context menu on a data point in a visualization).

In response to the user interaction, the code:

  1. Publishes an INVOKE_DATA_ACTION event containing the data action's ID, the DataVisualization that the data action is invoked from, and a TransientVizContext object.
  2. The DataActionManager handles this event by:
    1. Obtaining the data action instance from its ID.
    2. Obtaining the LogicalFilterTrees for the marked data points in the specified DataVisualization.
    3. Constructing a DataActionContext that contains all the information to pass to the data action's target.
    4. Calling invoke(oDataActionContext) on the data action.

Example Data Action plugin.xml File

This topic shows an example plugin.xml file for a CanvasDataAction data action.

Example plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<tns:obiplugin xmlns:tns="http://plugin.frameworks.tech.bi.oracle"
               xmlns:viz="http://plugin.frameworks.tech.bi.oracle/extension-points/vizualization"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               id="obitech-currencyconversion"
               name="Oracle BI Currency Conversion"
               version="0.1.0.@qualifier@"
               optimizable="true"
               optimized="false">
 
 
   <tns:resources>
      <tns:resource id="currencyconversion" path="scripts/currencyconversion.js" type="script" optimizedGroup="base"/>
      <tns:resource-folder id="nls" path="resources/nls" optimizable="true">
         <tns:extensions>
            <tns:extension name="js" resource-type="script"/>
         </tns:extensions>
      </tns:resource-folder>
   </tns:resources>
 
 
   <tns:extensions>
      <tns:extension id="oracle.bi.tech.currencyconversiondataaction" point-id="oracle.bi.tech.plugin.dataaction" version="1.0.0">
         <tns:configuration>
         {
            "resourceBundle": "obitech-currencyconversion/nls/messages",
            "properties":
            {
               "className": "obitech-currencyconversion/currencyconversion.CurrencyConversionDataAction",
               "displayName": { "key" : "CURRENCY_CONVERSION", "default" : "Currency Conversion" },
               "order": 100
            }
         }
         </tns:configuration>
      </tns:extension>
   </tns:extensions>
 
 
</tns:obiplugin>

Data Action Plug-in Files and Folders

The following files and folders are used to implement data action plug-ins.

bitech/client/plugins/src/
  • report
    • obitech-report
      • scripts
        • dataaction
          • dataaction.js
          • dataactiongadgets.js
          • dataactionpanel.js
          • dataactionupgradehandler.js
  • obitech-reportservice
    • scripts
      • dataaction
        • dataactionmanager.js
        • dataactionhandler.js

Choose the Best Data Action Class to Extend

Before you start writing your custom data action plug-in, decide which of the existing data action classes you want to extend. Choose the data action class that provides functionality that most closely matches what you want your data action to do.

Each data action inherits from the AbstractDataAction class as shown in the class diagram. The class diagram shows the two abstract data action classes (AbstractDataAction and AbstractHTTPDataAction) and the four concrete data action classes (CanvasDataAction, URLNavigationDataAction, HTTPAPIDataAction, and EventDataAction) that you can extend. Each data action that you provide must extend one of these classes. Which class you extend depends on the behavior you want to implement when you invoke your data action. Most third-party data actions are likely to extend either URLNavigationDataAction, HTTPAPIDataAction or EventDataAction.

Data action class diagram showing the classes that you can extend.

Regardless of which class you extend, when your data action is invoked, you're provided with metadata describing the full context of the data-point from which the data action is invoked. See Data Action Context.

AbstractDataAction Class

AbstractDataAction is the abstract base class from which all types of data action inherit. It's responsible for providing common functionality and default behavior that the subclasses can use.

AbstractDataAction

All types of data action are subclasses of the AbstractDataAction base class. It provides the core set of functionality common to all data actions. Unless you're creating a complex data action that carries out multiple types of action when invoked, or you need to do something not supported by the concrete classes, you shouldn't extend this class directly. If you need to create a complex data action then consider extending the concrete class that most closely provides the functionality you require.

AbstractDataAction Syntax

+ AbstractDataAction(oKOModel)

+ getKOViewModel():DataActionKOModel

+ createFromJS(fDataActionConstructor, sClassName, oDataActionKOModelUS) : AbstractDataAction
+ invoke(oActionContext, oDataActionContext)
+ getGadgetInfos(oReport) : AbstractGadgetInfo[]
+ validate() : DataActionError
+ getSettings() : Object
+ requiresActionContextToInvoke() : Boolean
+ isAllowedHere() : Boolean
# createNameGadgetInfo(oReport) : AbstractGadgetInfo
# createAnchorToGadgetInfo(oReport) : AbstractGadgetInfo
# createPassValuesGadgetInfo(oReport) : AbstractGadgetInfo

DataActionKOModel Class

Each subclass of AbstractDataAction is likely to create its own subclass of DataActionKOModel. The DataActionKOModel base class provides the following properties:

DataActionKOModel, ValuePassingMode

  • sID:String

    The unique ID given to the data action instance.

  • sClass:String

    The class name of this specific type of data action.

  • sName:String

    The display name given to the data action instance.

  • sVersion
  • sScopeID
  • eValuePassingMode:ValuePassingMode

    The mode used when passing context values. The mode can be one of the ValuePassingMode values (ALL, ANCHOR_DATA, NONE, CUSTOM).

  • aAnchorToColumns: ColumnKOViewModel[]

    The columns that this data action is anchored to. This is optional. If not supplied, then the data action is available on all columns.

  • aContextColumns : ColumnKOViewModel[]

    The columns that this data action includes in the context passed to the data action target when the data action is invoked. If not supplied, all marked columns are included in the context.

CanvasDataAction Class

CanvasDataAction is a subclass of the AbstractDataAction base class. You can extend this concrete class to provide the functionality you require.

CanvasDataAction

Use the CanvasDataAction class to navigate from a data point in a visualization to a different canvas. The canvas you're navigating to can be in the same project or a different one. All the active filters for the source visualization are passed to the target canvas along with new filters that describe the Qualified Data Reference of the data point itself. If your data action needs to navigate to a different canvas then this is the class your data action should extend.

+ CanvasDataAction(oKOModel)

+ create(s)ID_sName) : CanvasDataAction
+ upgrade(oOldDataActionJS) : Object

+ invoke(oActionContext: ActionContext, oDataActionContext:DataActionContext)
+ getGadgetInfos(oReport) : AbstractGadgetInfo[]
+ validate() : DataActionError
# createProjectGadgetInfo(oReport) : AbstractGadgetInfo
# createCanvasGadgetInfo(oReport) : AbstractGadgetInfo

EventDataAction Class

EventDataAction is a subclass of the AbstractDataAction base class. You can extend this concrete class to provide the functionality you require.

EventDataAction

Use the EventDataAction class to publish a client-side event. You can then register one or more subscribers that listen for that event and perform their own actions. Use this type of data action in more complex use cases where you've a large amount of code and can benefit from keeping your data action code loosely coupled to the code that performs the necessary actions when the data action is invoked.

+ EventDataAction(oKOModel)

+ create(sID_sName) : EventDataAction
+ upgrade(oOldDataActionJS) : Object
+ invoke(oActionContext: ActionContext, oDataActionContext:DataActionContext)
+ getGadgetInfos(oReport) : AbstractGadgetInfo[]
+ validate() : DataActionError
# createEventGadgetInfo(oReport) : AbstractGadgetInfo

AbstractHTTPDataAction Class

AbstractHTTPDataAction is the abstract base class that the URLNavigationDataAction and HTTPAPIDataAction subclasses inherit common functionality and default behavior from.

AbstractHTTPDataAction

The AbstractHTTPDataAction abstract base class is shared by both the URLNavigationDataAction and HTTPAPIDataAction classes. If your data action needs to open a web page in a new browser tab you must extend URLNavigationDataAction. If your data action needs to invoke an HTTP API then you should extend HTTPAPIDataAction. You may decide it's better to extend AbstractHTTPDataAction directly.

+ HTTPDataAction(oKOModel)
+ validate() : DataActionError
# createURLGadgetInfo(oReport) : AbstractGadgetInfo

URLNavigationDataAction Class

URLNavigationDataAction is a subclass or the AbstractHTTPDataAction base class.

URLNavigationDataAction

Use the URLNavigationDataAction class to open a specific URL in a new browser tab. You compose the URL using tokens that are replaced with values derived from data points that the user selects when they invoke the data action. The data point values are passed as part of the data action context to the external web page. For example, create a data action invoked using a CustomerID column that opens a customer's web page in your Customer Relations Management application such as Oracle Sales Cloud.

+ URLNavigationDataAction(oKOModel)
+ create(sID_sName) : URLNavigationDataAction
+ upgrade(oOldDataActionJS) : Object
+ invoke(oActionContext: ActionContext, oDataActionContext:DataActionContext)
+ getGadgetInfos(oReport) : AbstractGadgetInfo[]

HTTPAPIDataAction Class

HTTPAPIDataAction is a subclass or the AbstractHTTPDataAction base class. You can extend this concrete class to provide the functionality you require.

HTTPAPIDataAction

Use the HTTPAPIDataAction class to invoke HTTP APIs by creating an asyncronous XMLHTTPRequest (XHR) and submitting it to the specified URL. The HTTP response code enables a message to be displayed briefly on the canvas. For example, you can customize the request to send JSON or XML payloads to a REST or SOAP server and you can customize the response handler to show a custom user interface.

For the HTTPAPIDataAction data action to work, you must add the URL of the HTTP API you want to access to your list of Safe Domains and grant it Connect access. See Whitelist Safe Domains.

+ HTTPAPIDataAction(oKOModel)
+ create(sID_sName) : HTTPAPIDataAction
+ upgrade(oOldDataActionJS) : Object
+ invoke(oActionContext: ActionContext, oDataActionContext:DataActionContext)
+ getGadgetInfos(oReport) : AbstractGadgetInfo[]
# createHTTPMethodGadgetInfo(oReport) : AbstractGadgetInfo
# createPostParamGadgetInfo(oReport) : AbstractGadgetInfo

Generate Data Action Plug-ins from a Template

You use a series of commands to generate a development environment and populate it with a HTTP API Data Action along with the necessary folders and files that you need to create a custom data action plug-in.

All Oracle Analytics Cloud plug-in files follow the same basic structure. You can manually create the files and folders or you can generate them from a template. The tools to do this are part of the Oracle Analytics Desktop software development kit (SDK) which is included with Oracle Analytics Desktop. See Oracle Analytics Desktop SDK Reference.

Use Oracle Analytics Desktop version 5.4 or later to access the classes required to create a custom data action plug-in.

Use these commands to generate your development environment and populate it with a HTTP API data action.

  1. At a command prompt, specify the root folder of your Oracle Analytics Desktop installation:
    set DVDESKTOP_SDK_HOME=C:\Program Files\Oracle Analytics Desktop
  2. Specify the location to store your custom plug-ins:
    set PLUGIN_DEV_DIR=C:\temp\dv-custom-plugins
  3. Add the SDK command line tools to your path using:
    set PATH=%DVDESKTOP_SDK_HOME%\tools\bin;%PATH%
  4. Create a folder for the directory used to store the custom plug-ins using:
    mkdir %PLUGIN_DEV_DIR%
  5. Change the directory to the folder for storing custom plug-ins:
    cd %PLUGIN_DEV_DIR%
  6. Create the environment variables:
    bicreateenv
  7. Create the template files needed to start developing a custom HTTP API data action, for example:
    bicreateplugin -pluginxml dataaction -id company.mydataaction -subType httpapi

    Use the -subType option to specify the data action type that you want to create from: httpapi, urlNavigation, canvasNavigation, event, or advanced. The advanced option extends from the AbstractDataAction base class.

Generated Folders and Files

Your newly generated data action development environment contains these folders and files:


1    %PLUGIN_DEV_DIR%\src\customdataaction
2       company-mydataaction\
3          extensions\
4             oracle.bi.tech.plugin.dataaction\
5                company.mydataaction.json
6          nls\
7             root\
8                messages.js
9             messages.js
10          mydataaction.js
11          mydataactionstyles.css
12          plugin.xml
  • Line 2: The company-mydataaction folder is the ID that you specify.
  • Line 6: The nls folder contains the files for externalizing strings that enable your plug-in to provide Native Language Support.
  • Line 7: The strings in the files under the nls\root folder are the default strings used when translations for a requested language aren't available.
  • Line 8: The messages.js file contains externalized strings for your plug-in that you can add.
  • Line 9: The messages.js file must contain an entry that you add for each additional language that you want to provide localized strings for. You must add a corresponding folder under the nls folder for each locale that you want to add translations for. Each folder must contain the same set of files, with the same file names as those added under the nls\root folder.
  • Line 10: The mydataaction.js file is the newly generated JavaScript module template that provides a starting point to develop your custom data action.
  • Line 11: The mydataactionstyles.css file can contain any CSS styles that you want to add, and which your data action's user interface can use.
  • Line 12: The plugin.xml file registers your plug-in and its files with Oracle Analytics Cloud.

Extend a Data Action Base Class

Once you've chosen the subclass of data action that you want to extend and have generated the necessary folders and files, you're ready to start writing the code specific to your new data action.

You can find your newly generated data action code under %PLUGIN_DEV_DIR%\src\dataaction. See Generated Folders and Files for an explanation of the files and folder structure. The main file you must edit is the JavaScript file. For example, if your custom data action ID is company.MyDataaction, then the file you're looking for is %PLUGIN_DEV_DIR%\src\dataaction\company-mydataaction\mydataaction.js.

Extending Your Data Action's Knockout Model

If your data action has additional properties that need to be stored, then you must add them as observable properties to the Knockout Model. If your data action is given the ID company.MyDataaction, then the Knockout Model is called mydataaction.MyDataActionKOModel which is located near the top of mydataaction.js. By default, this Knockout Model is configured to extend the Knockout Model used by your data action's superclass so you only need to add additional properties to the model.

For a data action that's extending the HTTPAPIDataAction base class, use code similar to the following:

1 - mydataaction.MydataactionKOModel = function (sClass, sID, sName, sVersion, sScopeID, aAnchorToColumns, eValuePassingMode, sURL,
        eHTTPMethod, sPOSTParams)
2 - {   
3 - mydataaction.MydataactionKOModel.baseConstructor.call(this, sClass, sID, sName, sVersion, sScopeID, aAnchorToColumns, eValuePassingMode, sURL, eHTTPMethod, sPOSTParams);
4 - };
5 - jsx.extend(mydataaction.MydataactionKOModel, dataaction.HTTPAPIDataActionKOModel);
  • Line 1: This is the constructor for your Knockout Model. It accepts the properties that the model needs to store.
  • Line 3: This is the superclass's constructor, otherwise known as the baseConstructor to which you pass the values for all of the properties that are handled by one of the Knockout Model's superclasses.
  • Line 5: This sets the superclass for this Knockout Model class.

Use code similar to the following to add a string and an array to set properties that are persisted by the data action.

1   mydataaction.MydataactionKOModel = function (sClass, sID, sName, sVersion, sScopeID, aAnchorToColumns, eValuePassingMode, sURL, eHTTPMethod, sPOSTParams)
2   {   
3   mydataaction.MydataactionKOModel.baseConstructor.call(this, sClass, sID, sName, sVersion, sScopeID, aAnchorToColumns, eValuePassingMode, sURL, eHTTPMethod, sPOSTParams);
4   
5  
6   // Set Defaults   
7   sMyString = sMyString || "My default string value";   
8   aMyArray = aMyArray || [];     
9  
10
11  // Asserts   
12  jsx.assertString(sMyString, "sMyString");   
13  jsx.assertArray(aMyArray, "aMyArray");
14 
15
16  // Add observable properties   
17  this.sMyString = ko.observable(sMyString);   
18  this.aMyArray = ko.observableArray(aMyArray);
19  };
20  jsx.extend(mydataaction.MydataactionKOModel, dataaction.HTTPAPIDataActionKOModel);

Choose Which Data Action Inherited Methods to Override

Each data action must implement various methods in order to function properly, so you only need to override those methods that implement behavior that you want to change.

Generic Methods

If you're extending one of the concrete data actions classes, for example HTTPAPIDataAction, then most of the required methods are already implemented and you only need to override the methods that implement the behavior you want to change.

This section describes the various methods and what's expected of them.

All types of data action must implement the methods that are described here.

create(sID, sName)

The create() static method is called when you're creating a new data action and select a Data Action Type from the drop-down menu. This method is responsible for:

  • Constructing the Knockout Model class that your data action uses.

    The Knockout Model class must have the ID and name that's passed to the create() method along with sensible defaults for all other properties. For example, for a currency conversion data action you might want to set the default currency to convert into Dollars. The Knockout Model is the correct place to provide your default values.

  • Constructing an instance of your data action from the Knockout Model.
  • Returning the instance of your data action.

invoke(oActionContext, oDataActionContext)

The invoke() method is called when the user invokes your data action from the context menu for a data point in a visualization. The method passes the DataActionContext argument which contains metadata describing the selected data points, visualization, filters, project, and session. See Data Action Service Classes.

validate()

The validate() method is called on each data action when the user clicks OK in the Data Actions dialog. The validate() method returns a null to indicate that everything is valid or a DataActionError if something is invalid. If there's an error in one of the data actions in the dialog, the error prevents the dialog from closing and an error message is displayed to the user. This method validates the name of the data action using the this.validateName() method.

getGadgetInfos(oReport)

The getGadgetInfos() method is called to enable the user interface to display data action property fields. The method returns an array of GadgetInfos in the order you want them to appear in the user interface. Gadgets are provided for all of the most common types of fields (for example, text, drop-down, password, multi-select, radio button, check box) but you can create custom gadgets if you want more complicated fields (for example, where multiple gadgets are grouped together, or where different gadget fields display depending on which option you select). It's a best practice to create a method that constructs each GadgetInfo you want in your array, as it makes it easier for potential subclasses to pick and choose from the GadgetInfos you've provided. If you follow this best practice there are already various methods implemented by the different data action base classes that can return a GadgetInfo for each of the fields that they use in their user interfaces. If you also need one of these GadgetInfos then you call the corresponding create****GadgetInfo() method and push its return value into your array of gadgets.

isAllowedHere(oReport)

The isAllowedHere() method is called when the user right-clicks on a data-point in a visualization and the user interface starts to generate the context menu. If a data action exists that's relevant to the selected data-points, then the method returns true and the data action appears in the context menu. If the method returns false, then the data action doesn't appear in the context menu. Consider accepting the default behavior inherited from the superclass.

upgrade(oOldDataActionJS)

If you're creating your first data action then don't use the upgrade(oOldDataActionJS) method. Only use this method after you've created your first Knockout Model and are making significant changes to properties for a second version of your Knockout Model. For example, if the first version of your data action stores a URL in its Knockout Model, but you decide that the next version will store URL component parts in separate properties (for example, protocol, hostname, port, path, queryString and bookmark).

The second version of your Knockout Model code would request to open a data action that had been saved with the first version of your Knockout Model code which can cause problems. To resolve this issue, the system identifies that your current data action code version is newer than that of the data action being opened and it calls the upgrade() method on your new data action class and passes in the old data action Knockout Model (serialized to a JSON object). You can then use the old JSON object to populate your new Knockout Model and return an upgraded version of the JSON object. This ensures that old data action metadata continues to work as you improve your data action code.

HTTPAPIDataAction Methods

If you're extending the HTTPAPIDataAction class, then it provides the following additional method that you may choose to override:

getAJAXOptions(oDataActionContext)

The getAJAXOptions() method is called by the data action's invoke() method. The getAJAXOptions() method creates the AJAX Options object that describes the HTTP request that you want your data action to make. The getAJAXOptions() method is passed the oDataActionContext object that contains the metadata describing the selected data-points, visualization, filters, project, and session. Set the AJAX Options as required by the HTTP API you're trying to integrate with and specify the functions you want to be called when the HTTPRequest is successful or results in an error. See the JQuery website for an explanation of the jQuery.ajax object and its properties.

The following implementation is inherited from the HTTPAPIDataAction class. You need to rewrite the inherited method to specify requirements. For example, forming the HTTP request, and the code that handles the HTTP response. This implementation is useful as it shows the parameters passed to the getAJAXOptions() function, the object that it's expected to return, and gives a clear example of how to structure the code inside the method.

1 /**
2  * This method returns an object containing the AJAX settings used when the data action is invoked. 
3  * Subclasses may wish to override this method to provide their own behavior. 
4  * @param {module:obitech-reportservices/dataactionmanager.DataActionContext} oDataActionContext The context metadata describing where the data action was invoked from.  
5  * @returns {?object} A JQuery AJAX settings object (see http://api.jquery.com/jQuery.ajax/ for details) - returns null if there is a problem. 
6  */
7 dataaction.HTTPAPIDataAction.prototype.getAJAXOptions = function (oDataActionContext)
8 {
9    jsx.assertInstanceOfModule(oDataActionContext, "oDataActionContext", "obitech-reportservices/dataactionmanager", "DataActionContext");
10   
11   var oAJAXOptions = null;   
12   var oKOViewModel = this.getKOViewModel();
13   var sURL = oKOViewModel.sURL();
14   if (sURL)
15   {
16      // Parse the URL
17      var sResultURL = this._parseURL(sURL, oDataActionContext);
18      if (sResultURL)
19      {
20         // Parse the POST parameters (if required)
21         var eHTTPMethod = oKOViewModel.eHTTPMethod()[0];
22         var sData = null;
23         if (eHTTPMethod === dataaction.HTTPDataActionKOModel.HTTPMethod.POST)
24         {
25            var sPOSTParams = oKOViewModel.sPOSTParams();
26            sData = sPOSTParams.replace(dataaction.AbstractHTTPDataAction.RegularExpressions.LINE_END, "&");
27            sData = this._parseURL(sData, oDataActionContext, false);
28         }
29         oAJAXOptions = {
30            type: eHTTPMethod,
31            url: sResultURL,
32            async: true,
33            cache: false,
34            success: function (/*oData, sTextStatus, oJQXHR*/)
35            {
36               oDataActionContext.getReport().displaySuccessMessage(messages.HTTP_API_DATA_ACTION_INVOCATION_SUCCESSFUL.format(oKOViewModel.sName()));
37            },
38            error: function (oJQXHR/*, sTextStatus, sError*/)
39            {
40               oDataActionContext.getReport().displayErrorMessage(messages.HTTP_API_DATA_ACTION_INVOCATION_FAILED.format(oKOViewModel.sName(), oJQXHR.statusText, oJQXHR.status));
41            }
42         };
43         if (sData)
44         {
45            oAJAXOptions.data = sData;
46         }
47      }
48   }
49   return oAJAXOptions;
50 };

Test, Package, and Install Your Data Action

You use Oracle Analytics Desktop to test your data action from its source location before you install it.

  1. If Oracle Analytics Desktop is currently running, close it.
  2. If you're working behind a proxy, set the proxy settings in %PLUGIN_DEV_DIR%\gradle.properties. For information about accessing the web through HTTP proxy, see Gradle User Manual.
  3. Run Oracle Analytics Desktop in SDK mode by using the command prompt you started in Choose Which Data Action Inherited Methods to Override and enter the following commands:
    cd %PLUGIN_DEV_DIR%
    .\gradlew run

    Oracle Analytics Desktop starts in SDK mode. Your data action plug-in appears in the Console | Extensions page.

    Create a project and test your data action. If you find any issues, you can debug your code using your browser's built-in developer tools.

  4. If you created an HTTP API data action:
    1. Go to the Console and display the Safe Domains page.
    2. Add each domain that you want to access.
      For example, if you need access to the apilayer.com APIs, add apilayer.net to the list of safe domains.
    3. Click the Connect column checkbox for the selected domain.
    4. Reload the Safe Domains page in your browser for the changes to take effect.
  5. If you want to prepare your data action plug-in to distribute to other people or to install in Oracle Analytics Cloud:
    • Package all of the files into a single ZIP file containing the %PLUGIN_DEV_DIR%\src\customdataaction folder and its contents.
    • Name the zip using the same ID you gave to your data action plug-in when you created it.
  6. Install your data action plug-in. See Manage Custom Plug-ins.

Use an Upgrade Handler for Knockout Model Changes

For some Knockout Model changes you need to upgrade your data action plug-in using an upgrade handler.

When you're making improvements to your data action plug-in without making changes to the Knockout Model you normally edit your JavaScript or CSS files, create a new ZIP file, and replace the existing data action plug-in with the new ZIP file. However, if you've made changes to your data action's Knockout Model then you might need to change the data action VERSION property and provide an upgrade handler.

Decide whether you need to use an upgrade handler:

Upgrade Handler Required
  • If you rename a property in your Knockout Model.
  • If you combine multiple properties into a single property in your Knockout Model.
  • If you split a single property into multiple properties in your Knockout Model.
  • If you add a new property to the Knockout Model and the correct default value for it depends on other values in the Knockout Model.
Upgrade Handler Not Required
  • If you add a new property to the Knockout Model and can provide a default value that's correct for all existing usages of your data action.
  • If you remove a property from the Knockout Model because it's no longer used by your data action code.

Upgrade Data Action Plug-ins

Upgrade your data action plug-ins to improve the data action code or upgrade the metadata to enable existing data actions to work with new data action code.

Use an upgrade handler to upgrade a data action plug-in.
  1. Increase the version number of your data action.

    For example, if your data action is called company.MyDataAction, then search mydataaction.js for the mydataaction.MyDataAction.VERSION property. If it's currently set to 1.0.0 then change it to 1.0.1.

  2. Add a static upgrade(oOldDataActionJS) method to your data action's class.

    If the VERSION property differs from the sVersion value stored in the data action metadata then the Data Action Manager calls the static upgrade() method on your data action's class.

  3. Implement your upgrade() method by calling the upgrade() method on the superclass and capture its response.
  4. Continue to implement your upgrade() method by making further edits to the partially upgraded data action JSON returned by the superclass, until the object matches the correct set of properties required by your latest Knockout Model.
  5. To finish call var oUpgradedDataAction = dataaction.AbstractDataAction.createFromJS(fDataActionClass, sFullyQualifiedDataActionClassName, oUpgradedDataActionJS).

    This command constructs a new instance of your data action from the upgraded data action JSON and returns oUpgradedDataAction.getSettings().

Data Action Plug-in File Reference

Each data action plug-in requires a plugin.xml file and each plugin.xml file can contain any number of data actions.

Data Action plugin.xml File Example

The plugin.xml file has three main sections, tns:obiplugin, tns:resources, and tns:extension.

Example plugin.xml

This example shows a typical plugin.xml file for one data action.

1 <?xml version="1.0" encoding="UTF-8"?>
2 <tns:obiplugin xmlns:tns="http://plugin.frameworks.tech.bi.oracle"
3                id="obitech-currencyconversion"
4                name="Oracle BI Currency Conversion"
5                version="0.1.0.@qualifier@"
6                optimizable="true"
7                optimized="false">
8 
9 
10   <tns:resources>
11      <tns:resource id="currencyconversion" path="scripts/currencyconversion.js" type="script" optimizedGroup="base"/>
12      <tns:resource-folder id="nls" path="resources/nls" optimizable="true">
13         <tns:extensions>
14            <tns:extension name="js" resource-type="script"/>
15         </tns:extensions>
16      </tns:resource-folder>
17   </tns:resources>
18  
19 
20   <tns:extensions>
21      <tns:extension id="oracle.bi.tech.currencyconversiondataaction" point-id="oracle.bi.tech.plugin.dataaction" version="1.0.0">
22         <tns:configuration>
23         {
24            "host": { "module": "obitech-currencyconversion/currencyconversion" },
25            "resourceBundle": "obitech-currencyconversion/nls/messages",
26            "properties":
27            {
28               "className": "obitech-currencyconversion/currencyconversion.CurrencyConversionDataAction",
29               "displayName": { "key" : "CURRENCY_CONVERSION", "default" : "Currency Conversion" },
30               "order": 100
31            }
32         }
33         </tns:configuration>
34      </tns:extension>
35   </tns:extensions>
36 
37 </tns:obiplugin>

Data Action plugin.xml File Properties Section - tns:obiplugin

The tns:obiplugin section defines properties common to all types of plug-ins.

Plug-in Properties

The tns:obiplugin section defines properties common to all types of plug-ins.

1 <?xml version="1.0" encoding="UTF-8"?>
2 <tns:obiplugin xmlns:tns="http://plugin.frameworks.tech.bi.oracle"
3                id="obitech-currencyconversion"
4                name="Oracle BI Currency Conversion"
5                version="0.1.0.@qualifier@"
6                optimizable="true"
7                optimized="false">
  • Line 1: The XML declaration.
  • Line 2: The opening tag for the plug-in's root XMLElement and the declaration for the tns namespace that's used throughout plugin.xml files.
  • Line 3: The plug-in's unique ID.
  • Line 4: The plug-in's default display name (used when a localized version isn't available).
  • Line 5: The plug-in's version number.
  • Line 6: A boolean indicating whether or not the JS/CSS can be optimized (compressed).
  • Line 7: A boolean indicating whether or not the JS/CSS has been optimized (compressed).

Data Action plugin.xml File Resources Section - tns:resources

The tns:resources section registers all of the files that contribute to your plug-in.

Resources


1 <tns:resources>
2    <tns:resource id="currencyconversion" path="scripts/currencyconversion.js" type="script" optimizedGroup="base"/>
3    <tns:resource-folder id="nls" path="resources/nls" optimizable="true">
4       <tns:extensions>
5          <tns:extension name="js" resource-type="script"/>
6       </tns:extensions>
7    </tns:resource-folder>
8 </tns:resources>

You need to register each JavaScript, CSS, Image, and Translation Resource File here. The section is contained within the <tns:resources> element and contains any number of the following elements:

  • <tns:resource>

    These elements are used to register a single file (for example, a JavaScript or CSS file).

  • <tns:resource-folder>

    These elements are used to register all the files under a specified folder at the same time. For example, an image folder or the folder containing the resource files for Native Language Support.

More information on how to register each type of file is provided in the following sections.

JavaScript Files

Each JavaScript file in your plug-in must be registered with a line similar to the one shown below.

<tns:resource id="currencyconversion" path="scripts/currencyconversion.js" type="script" optimizedGroup="base"/>

Where:

  • id is the ID given to the file.

    Set the ID to match the JavaScript filename without the .js extension.

  • path is the relative path to the JavaScript file from the plugin.xml file. JavaScript files should be stored under your plug-in's scripts directory.

    Use all lowercase for your JavaScript files with no special characters (for example, underscore, hyphen).

  • type is the type of file being registered. It must be set to script for JavaScript files.
  • optimizedGroup groups multiple JavaScript files into a single compressed file. Third-party plug-ins must leave this set to base.

CSS Files

Each CSS file in your plug-in must be registered with a line similar to the one shown below.

<tns:resource id="currencyconversionstyles" path="resources/currencyconversion.css" type="css"/>

Where:

  • id is the ID given to the file.

    Set the ID to match the CSS filename without the .css extension.

  • path is the relative path to the CSS file from the plugin.xml file. CSS files should be stored under your plug-in's resources directory.

    Use all lowercase for your CSS files with no special characters (for example, underscore, hyphen).

  • type is the type of file being registered. It should always be set to css for CSS files.

Image Folders

If your plug-in has images that you need to refer to from within your JavaScript code, then put them in a resources/images directory within your plug-in's directory structure and add a <tns:resource-folder> element to your plugin.xml as follows:

<tns:resource-folder id="images" path="resources/images" optimizable="false"/>

If your images are only referenced by your CSS files, then you don't need to add this <tns:resource-folder> element to your plugin.xml file. In this case, you must still add them to the resources/images directory so that you can then refer to them using a relative path from your CSS file.

Native Language Support Resource Folders

Analytics Cloud implements Native Language Support. This requires developers to externalize the strings they display in their user interface into separate JSON resource files. You can then provide different localized versions of those files in a prescribed directory structure and Analytics Cloud automatically uses the correct file for the user's chosen language. You can provide as many translated versions of the resource files as needed. A Native Language Support resource folder points Analytics Cloud to the root of the prescribed Native Language Support directory structure used by your plug-in. All plug-ins that use Native Language Support resource files must have a <tns:resource-folder> entry that looks exactly like the example below.


1 <tns:resource-folder id="nls" path="resources/nls" optimizable="true">
2    <tns:extensions>
3       <tns:extension name="js" resource-type="script"/>
4    </tns:extensions>
5 </tns:resource-folder>

See Generated Folders and Files for details about the contents of the files and the prescribed directory structure that you should follow.

Data Action plugin.xml File Extensions Section - tns:extension

For each data action you want your plug-in to provide, you must register a data action extension using a <tns:extension> element similar to this:

<tns:extension id="oracle.bi.tech.currencyconversiondataaction" point-id="oracle.bi.tech.plugin.dataaction" version="1.0.0">
   <tns:configuration>
   {
      "host": { "module": "obitech-currencyconversion/currencyconversion" },
      "resourceBundle": "obitech-currencyconversion/nls/messages",
      "properties":
      {
         "className": "obitech-currencyconversion/currencyconversion.CurrencyConversionDataAction",
         "displayName": { "key" : "CURRENCY_CONVERSION", "default" : "Currency Conversion" },
         "order": 100
      }
   }
   </tns:configuration>
</tns:extension>

Where:

  • id is the unique ID you give to your data action.
  • point-id is the type of extension you want to register. For data action extensions, this must be set to oracle.bi.tech.plugin.dataaction.
  • version is the extension API version that your extension definition uses (leave this set to 1.0.0).

The <tns:configuration> element contains a JSON string that defines:

  • host.module - This is the fully qualified name of the module containing your data action. This fully qualified module name is formulated as %PluginID%/%ModuleName%, where:
    • %PluginID% must be replaced with the plug-in ID you specified in the id attribute of the <tns:obiplugin> element.
    • %ModuleName% must be replaced with the resource ID you specified in the id attribute of the <tns:resource> element for the JavaScript file containing your data action.
  • resourceBundle - This is the Native Language Support path to the resource file that contains this data action's localized resources. If your resource files are named messages.js and stored correctly in the prescribed nls directory structure, then set this property to %PluginID%/nls/messages (where %PluginID% must be replaced with the plug-in ID you specified in the id attribute of the <tns:obiplugin> element at the top of the plugin.xml file).
  • properties.className - This is the fully qualified class name given to the data action you're registering. This fully qualified class name is formulated as %PluginID%/%ModuleName%.%ClassName%, where:
    • %PluginID% must be replaced with the plug-in ID you specified in the id attribute of the <tns:obiplugin> element.
    • %ModuleName% must be replaced with the resource ID you specified in the id attribute of the <tns:resource> element for the JavaScript file containing your data action.
    • %ClassName% must be replaced with the name you gave to the data action class in your JavaScript file.
  • properties.displayName - This property contains an object and two further properties:
    • key is the Native Language Support message key that can be used to lookup the data action's localized display name from within the specified resourceBundle.
    • default is the default display name to use if for some reason the localized version of the display name can't be found.
  • properties.order - This property enables you to provide a hint that's used to determine the position that this data action should appear when shown in a list of data actions. Data actions with lower numbers in their order property appear before data actions with higher numbers. When there's a tie, the data actions are displayed in the order they're loaded by the system.