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;
});