JavaScript Extension Development API for Oracle Visual Builder Cloud Service - Classic Applications

Source: bop/js/spi/operation/OperationProvider.js

define([
], function() {

    'use strict';

    /**
     * SPI object representing a single Operation Provider.
     *
     * <p>
     * {@link bop/js/spi/operation/OperationProvider OperationProvider} is responsible for providing all {@link operation/js/api/Operation Operation} that can be performed on {@link entity/js/api/Entity Entities} defined in
     * the corresponding {@link bop/js/spi/entity/EntityProvider EntityProvider}.
     * </p>
     *
     * <p>
     * For example, if you have REST service like this:
     *
     * <ul>
     *  <li>
     *      GET /employeeAll<br/>
     *      --> Which gets all employees. Assume only Fistname and Lastname fields are returned.
     *  </li>
     *  <li>
     *      GET /employee/{id}<br/>
     *      --> Which gets single employee defined using the given ID. Assume all fields (Firstname, Lastname, Age and Salary) are returned.
     *  </li>
     *  <li>
     *      CREATE /employee<br/>
     *      --> Which creates new employee.
     *  </li>
     *  <li>
     *      DELETE /employee/{id}<br/>
     *      --> Which delete employee using the given ID.
     *  </li>
     *  <li>
     *      UPDATE /employee/{id}<br/>
     *      --> Which updates data for employee with the given ID.
     *  </li>
     * </ul>
     *
     * Your {@link bop/js/spi/operation/OperationProvider OperationProvider} need to have the single {@link operation/js/api/Operation Operation} created for each of these REST calls. Those {@link operation/js/api/Operation Operation}s needs to be described precisely
     * using {@link bop/js/api/operation/OperationBuilder OperationBuilder}, {@link bop/js/api/operation/OperationInput OperationInput} and {@link bop/js/api/operation/OperationOutput OperationOutput} objects so that Application Builder allow Business User to use only
     * UI features that are supported by these REST call itself. For example {@link operation/js/api/Operation Operation} that correspond to the GET/employeeAll REST call, need to define and use different {@link bop/js/api/operation/OperationOutput OperationOutput}
     * because the REST call returns only two fields instead of the full set of them. Based to that information, Application Builder UI adapt automatically.
     * </p>
     *
     * <p>
     * {@link bop/js/spi/operation/OperationProvider OperationProvider} is one of the two main parts required to implement custom {@link bop/js/spi/BOP BOP}. The other one is {@link bop/js/spi/entity/EntityProvider EntityProvider}.
     * </p>
     *
     * @AbcsExtension stable
     * @version 17.1.1
     * @exports bop/js/spi/operation/OperationProvider
     *
     * @constructor
     * @private
     *
     * @see {@link bop/js/spi/BOP BOP}
     * @see {@link bop/js/spi/entity/EntityProvider EntityProvider}
     * @see {@link bop/js/api/operation/OperationInput OperationInput} to create description of the {@link operation/js/api/Operation Operation} input (e.g. which parameters are available, which of them are required, which {@link module:operation/js/api/Operator Operator}s are supported etc.)
     * @see {@link bop/js/api/operation/OperationOutput OperationOutput} to create description of the {@link operation/js/api/Operation Operation} output (e.g. which {@link entity/js/api/Property Properties} are returned by the REST call)
     * @see {@link bop/js/api/operation/OperationBuilder OperationBuilder} to create general description of the resulted {@link operation/js/api/Operation Operation} (defines for example name, description or {@link operation/js/api/Operation.Type Type} of the {@link operation/js/api/Operation Operation}).
     * @see {@link operation/js/api/Operation Operation} to check how resulted {@link operation/js/api/Operation Operation}s produced by this {@link bop/js/spi/operation/OperationProvider OperationProvider} look like.
     *
     * @example
     * <caption>
     *  Example of typical implementation of custom {@link bop/js/spi/operation/OperationProvider OperationProvider} used inside of the custom {@link bop/js/spi/BOP BOP}.
     * </caption>
     *
     * define([
     *     'operation/js/api/Operation',
     *     'operation/js/api/Operator',
     *     'bop/js/api/operation/OperationBuilder',
     *     'bop/js/api/operation/OperationInput',
     *     'bop/js/api/operation/OperationOutput',
     *     '{{package}}/js/Employee'
     * ], function (
     *     Operation,
     *     Operator,
     *     OperationBuilder,
     *     OperationInput,
     *     OperationOutput,
     *     Employee
     * ) {
     *
     *     var CustomOperationProvider = function () {
     *         this._operations = [];
     *
     *         var employee = Abcs.Entities().findById('my.custom.bop.Employee');
     *         var id = employee.getProperty('my.custom.bop.Employee.ID');
     *         var firstname = employee.getProperty('my.custom.bop.Employee.Firstname');
     *         var lastname = employee.getProperty('my.custom.bop.Employee.Lastname');
     *         var age = employee.getProperty('my.custom.bop.Employee.Age');
     *
     *         var partialOutput = new OperationOutput({
     *             entity: employee
     *         }).property(firstname).
     *             property(lastname);
     *
     *         var idInput = new OperationInput({
     *             entity: employee
     *         }).parameter({
     *             property: id,
     *             required: true
     *         });
     *
     *         var firstnameLastnameInput = new OperationInput({
     *             entity: employee
     *         }).parameter(firstname).
     *             parameter(lastname).
     *             operators([
     *                 Operator.EQUALS,
     *                 Operator.NOT_EQUALS,
     *                 Operator.STARTS_WITH,
     *                 Operator.ENDS_WITH,
     *                 Operator.CONTAINS,
     *                 Operator.NOT_CONTAINS
     *             ]);
     *
     *         var getAllEmployees = new OperationBuilder({
     *             name: 'Find all Employees',
     *             type: Operation.Type.READ_MANY,
     *             performs: function() {
     *                 // Assume there is an Employee object as part of our BOP extension implementation which builds the URL based
     *                 // on the "operationInputData" values, makes the real REST call and returns relevant OperationResult instance
     *                 return Promise.resolve(Employee.getAll());
     *             }
     *         }).description('Longer description of what this Operation does').
     *             returns(partialOutput).
     *             takes(firstnameLastnameInput).
     *             build();
     *
     *         var getEmployeeByID = new OperationBuilder({
     *             name: 'Find Employee by ID',
     *             type: Operation.Type.READ_ONE,
     *             performs: function(operationInputData) {
     *                 // Assume there is an Employee object as part of our BOP extension implementation which builds the URL based
     *                 // on the "operationInputData" values, makes the real REST call and returns relevant OperationResult instance
     *                 return Promise.resolve(Employee.findByID(operationInputData));
     *             }
     *         }).specialType(Operation.SpecialType.QUERY_BY_ID).
     *             takes(idInput).
     *             returns(employee).
     *             build();
     *
     *         // Register all relevant operations
     *         this._operations.push(getAllEmployees);
     *         this._operations.push(getEmployeeByID);
     *
     *         // ..include the same for all other REST calls
     *     };
     *
     *     CustomOperationProvider.prototype.getOperations = function() {
     *         return this._operations;
     *     };
     *
     *     return CustomOperationProvider;
     * });
     *
     * @example
     * <caption>
     *  Example of typical implementation of custom {@link bop/js/spi/operation/OperationProvider OperationProvider} used inside of the custom {@link bop/js/spi/BOP BOP}
     *  that defines a {@link bop/js/spi/resource/ResourceProvider ResourceProvider} so that it can make use of the default
     *  {@link bop/js/spi/operation/OperationProvider#getAuthenticator authenticator}
     * </caption>
     *
     * define([
     *     'bop/js/api/operation/BOPAuthenticators',
     *     'bop/js/api/operation/OperationBuilder',
     *     'bop/js/api/operation/OperationInput',
     *     'bop/js/api/operation/OperationOutput',
     *     'operation/js/api/Operation',
     *     'operation/js/api/Operator'
     * ], function (
     *     BOPAuthenticators,
     *     OperationBuilder,
     *     OperationInput,
     *     OperationOutput,
     *     Operation,
     *     Operator
     * ) {
     *
     *     var CustomOperationProvider = function (dependencies) {
     *         var self = this;
     *         this._dependencies = dependencies;
     *         this._operations = [];
     *
     *         var employee = Abcs.Entities().findById('my.custom.bop.Employee');
     *         var id = employee.getProperty('my.custom.bop.Employee.ID');
     *         var firstname = employee.getProperty('my.custom.bop.Employee.Firstname');
     *         var lastname = employee.getProperty('my.custom.bop.Employee.Lastname');
     *         var age = employee.getProperty('my.custom.bop.Employee.Age');
     *
     *         var employeeCollectionResouce = 'my.custom.bop.Employee[]'
     *         var employeeResouce = 'my.custom.bop.Employee'
     *
     *         var partialOutput = new OperationOutput({
     *             entity: employee
     *         }).property(firstname).
     *             property(lastname);
     *
     *         var idInput = new OperationInput({
     *             entity: employee
     *         }).parameter({
     *             property: id,
     *             required: true
     *         });
     *
     *         var firstnameLastnameInput = new OperationInput({
     *             entity: employee
     *         }).parameter(firstname).
     *             parameter(lastname).
     *             operators([
     *                 Operator.EQUALS,
     *                 Operator.NOT_EQUALS,
     *                 Operator.STARTS_WITH,
     *                 Operator.ENDS_WITH,
     *                 Operator.CONTAINS,
     *                 Operator.NOT_CONTAINS
     *             ]);
     *
     *         var getAllEmployees = new OperationBuilder({
     *             name: 'Find all Employees',
     *             type: Operation.Type.READ_MANY,
     *             performs: function() {
     *                 // Make an AJAX request to get hold of the list of employees
     *                 return self.getAuthenticator({
     *                    url : ....
     *                    method : ....
     *                 });
     *             }
     *         }).description('Longer description of what this Operation does').
     *             returns(partialOutput).
     *             takes(firstnameLastnameInput).
     *             build();
     *
     *         var getEmployeeByID = new OperationBuilder({
     *             name: 'Find Employee by ID',
     *             type: Operation.Type.READ_ONE,
     *             performs: function(operationInputData) {
     *                 // Make an AJAX request to get hold of the detauls of an
     *                 // employee
     *                 return self.getAuthenticator({
     *                    url : ....
     *                    method : ....
     *                 });
     *             }
     *         }).specialType(Operation.SpecialType.QUERY_BY_ID).
     *             takes(idInput).
     *             returns(employee).
     *             build();
     *
     *         // Register all relevant operations
     *         this._operations.push(getAllEmployees);
     *         this._operations.push(getEmployeeByID);
     *
     *         // ..include the same for all other REST calls
     *     };
     *
     *     CustomOperationProvider.prototype.getOperations = function() {
     *         return this._operations;
     *     };
     *
     *     // Required if using the built in authenticator
     *     CustomOperationProvider.prototype.getAuthenticator = function() {
     *         return BOPAuthenticators.getDefault(
     *             this._dependencies,
     *             new CustomResourceProvider());
     *     };
     *
     *     return CustomOperationProvider;
     * });
     *
     * define([
     *     'bop/js/api/resource/Resource',
     *     'bop/js/spi/resource/ResourceProvider'
     * ], function (
     *     Resource,
     *     ResourceProvider
     * ) {
     *
     *     var CustomResourceProvider = function () {
     *         var parent = Resource.create({
     *             id : 'employee_collection',
     *             template : '/employee',
     *             entity : 'my.custom.bop.Employee'
     *         });
     *         var child = Resource.createChild(parent, {
     *             id : 'employee_instance',
     *             template : '{id}',
     *         });
     *
     *         this._resources = [parent, child];
     *     };
     *
     *     CustomResourceProvider.prototype.getResources = function() {
     *         return this._resources;
     *     };
     *
     *     return CustomResourceProvider;
     * });
     */
    var OperationProvider = function() {
        AbcsLib.checkThis(this);
    };

    /**
     * Gets the array of {@link operation/js/api/Operation Operation}s provided by this {@link bop/js/spi/operation/OperationProvider OperationProvider}.
     *
     * @AbcsExtension stable
     * @version 17.1.1
     *
     * @returns {operation/js/api/Operation[]}
     */
    OperationProvider.prototype.getOperations = function() {
        return [];
    };

    /**
     * Returns the default implementation of {@link bop/js/api/operation/BOPAuthenticator} but it need to be overriden in most cases to define the white list of
     * allowed resources and there mappings to entities.
     *
     * @AbcsExtension stable
     * @version 17.1.1
     *
     * @returns {bop/js/spi/operation/BOPAuthenticator} - The {bop/js/spi/operation/BOPAuthenticator} for this provider.
     *
     * @example
     * <caption>
     *  Example of typical implementation of custom {@link bop/js/spi/operation/OperationProvider OperationProvider} used inside of the custom {@link bop/js/spi/BOP BOP}
     *  that defines a {@link bop/js/spi/resource/ResourceProvider ResourceProvider} so that it can make use of the default
     *  {@link bop/js/spi/operation/OperationProvider#getAuthenticator authenticator}
     * </caption>
     *
     * define([
     *     'bop/js/api/operation/BOPAuthenticators',
     *     'bop/js/api/operation/OperationBuilder',
     *     'bop/js/api/operation/OperationInput',
     *     'bop/js/api/operation/OperationOutput',
     *     'operation/js/api/Operation',
     *     'operation/js/api/Operator'
     * ], function (
     *     BOPAuthenticators,
     *     OperationBuilder,
     *     OperationInput,
     *     OperationOutput,
     *     Operation,
     *     Operator
     * ) {
     *
     *     var CustomOperationProvider = function (dependencies) {
     *         this._dependencies = dependencies;
     *     };
     *
     *     CustomOperationProvider.prototype.getOperations = function() {
     *         return [];
     *     };
     *
     *     // Required if using the built in authenticator
     *     CustomOperationProvider.prototype.getAuthenticator = function() {
     *         return BOPAuthenticators.getDefault(
     *             this._dependencies,
     *             new CustomResourceProvider());
     *     };
     *
     *     return CustomOperationProvider;
     * });
     *
     * define([
     *     'bop/js/api/resource/Resource',
     *     'bop/js/spi/resource/ResourceProvider'
     * ], function (
     *     Resource,
     *     ResourceProvider
     * ) {
     *
     *     var CustomResourceProvider = function () {
     *         var parent = Resource.create({
     *             id : 'employee_collection',
     *             template : '/employee',
     *             entity : 'my.custom.bop.Employee'
     *         });
     *         var child = Resource.createChild(parent, {
     *             id : 'employee_instance',
     *             template : '{id}',
     *         });
     *
     *         this._resources = [parent, child];
     *     };
     *
     *     CustomResourceProvider.prototype.getResources = function() {
     *         return this._resources;
     *     };
     *
     *     return CustomResourceProvider;
     * });
     *
     * @example
     * <caption>
     *  Example of typical implementation of custom {@link bop/js/spi/operation/OperationProvider OperationProvider} used inside of the custom {@link bop/js/spi/BOP BOP}
     *  that defines a custom {@link bop/js/spi/operation/BOPAuthenticator BOPAuthenticator} so that it can provide it's own authentication method
     * </caption>
     *
     * define([
     *     'bop/js/api/operation/BOPAuthenticators',
     *     'bop/js/api/operation/OperationBuilder',
     *     'bop/js/api/operation/OperationInput',
     *     'bop/js/api/operation/OperationOutput',
     *     'operation/js/api/Operation',
     *     'operation/js/api/Operator'
     * ], function (
     *     BOPAuthenticators,
     *     OperationBuilder,
     *     OperationInput,
     *     OperationOutput,
     *     Operation,
     *     Operator
     * ) {
     *
     *     var CustomOperationProvider = function () {
     *     };
     *
     *     CustomOperationProvider.prototype.getOperations = function() {
     *         return [];
     *     };
     *
     *     // Required if using the built in authenticator
     *     CustomOperationProvider.prototype.getAuthenticator = function() {
     *         return new CustomBOPAuthenticator();
     *     };
     *
     *     return CustomOperationProvider;
     * });
     *
     * define([
     *     'bop/js/spi/operation/BOPAuthenticator',
     *     'operation/js/api/OperationResult'
     * ], function (
     *     BOPAuthenticator,
     *     OperationResult
     * ) {
     *
     *     var CustomBOPAuthenticator = function () {
     *     };
     *
     *     CustomBOPAuthenticator.prototype.invoke = function(authentication, ajaxObject) {
     *        return new Promise(function (fulfil, reject) {
     *
     *            ajaxObject.headers = ajaxObject.headers || {};
     *            ajavObject.headers['customAuthHeader'] = some key
     *
     *            // Based on the authenticator so far set up the ajax request
     *            // with sensible defaults
     *            //
     *            $.ajax(ajaxObjectClone).done(function (data, status, jqXHR) {
     *                fulfil(OperationResult.success(data));
     *            }).fail(function (jqXHR, textStatus, errorThrown) {
     *                reject(OperationResult.fail(textStatus, jqXHR.status));
     *            });
     *        });
     *     };
     *
     *     return CustomBOPAuthenticator;
     * });
     */
    OperationProvider.prototype.getAuthenticator = function() {
        return undefined;
    };

    return OperationProvider;

});