define(['core/js/api/utils/StringUtils'], function (StringUtils) {
'use strict';
/**
* An object representing a single Resource so that it is possible to relate
* a given REST request to a particularly entity in the model. For example
* this is used by the {@link bop/js/spi/operation/BOPAuthenticator BOPAuthenticator}
* on the server side to provide a whitelist of all resources exposed by
* a particular BOP.
*
* @version 17.1.1
* @AbcsExtension stable
* @exports bop/js/api/resource/Resource
*
* @constructor
* @private
**/
var Resource = function (data) {
this._id = data.id;
this._template = data.template;
this._entityId = data.entity;
this._parent_resource = data.parent_resource;
this._headers = data.headers;
};
/**
* @returns {String} The id if this resource
*/
Resource.prototype.getId = function () {
return this._id;
};
/**
* @returns {String} The URI template for this resource relative to the
* root of the service
*/
Resource.prototype.getTemplate = function () {
return this._template;
};
/**
* @returns {String} The entity that is represented by this resource
*/
Resource.prototype.getEntityId = function () {
return this._entityId;
};
/**
* @returns {String} The parent resource, normally a collection of self
*/
Resource.prototype.getParentResourceId = function () {
return this._parent_resource;
};
/**
* Returns the object that specifies the headers that can be sent to
* the REST API. The keys of the object are the name of the headers
* (in lowercase) and the value of each key is the expected value for
* the header, which can be expressed either has a string or as a
* regular expression. Headers that don't match this description
* are not sent to the REST API.
*
* @returns {Object} Undefined or the object that specifies the headers that can be
* sent to the REST API. The keys of the object are the name of the headers
* and the value of each key is the expected value for
* the header, which can be expressed either has a string or as a
* regular expression.
*
* @example
* <caption>
* Headers can be specified during the resouce creation. This example shows how to
* specify 3 headers that can be sent to the REST API: 'h1' whose value
* is the exact string 'http://www.example.com?summary', 'h2' whose value can be either
* 'test' or 'production', and 'h3' whose value is a phone number that matches the specified
* regular expression.
* </caption>
*
* var parent = Resource.create({
* id: 'employee_collection',
* template: '/employee',
* entity: 'my.custom.bop.Employee',
* headers: {
* h1: 'http://www.example.com?summary',
* h2: /test|production/,
* h3: /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/
* }
* });
*
*/
Resource.prototype.getHeaders = function () {
return this._headers;
};
/**
* An internal method to validate the basic data object.
*
* @param {type} data
*/
Resource._validateData = function (data) {
var mandatoryFields = [
'id',
'template',
'entity'
];
var supportedFields = mandatoryFields.concat([
'headers'
]);
AbcsLib.checkObjectLiteral(data, supportedFields, mandatoryFields);
};
/**
* A internal version of the factory method that doesn't check
* constrain the contents of data so that the nornal and child methods
* can pass in slightly different information
*/
Resource.createIntl = function (data) {
AbcsLib.checkDefined(data.id, 'data.id');
AbcsLib.checkDataType(data.id, AbcsLib.Type.STRING);
AbcsLib.checkDefined(data.template, 'data.template');
AbcsLib.checkDataType(data.template, AbcsLib.Type.STRING);
AbcsLib.checkDefined(data.entity, 'data.entity');
AbcsLib.checkDataType(data.entity, AbcsLib.Type.STRING);
if (AbcsLib.isDefined(data.headers)) {
AbcsLib.checkDataType(data.headers, AbcsLib.Type.OBJECT);
var headerNames = Object.keys(data.headers);
if (headerNames.length === 0) {
throw new Error('The "headers" object defined at least one header and value expression.');
}
headerNames.forEach(function (headerName) {
var headerValue = data.headers[headerName];
if (!AbcsLib.isRegExp(headerValue) && !AbcsLib.isString(headerValue)) {
throw new Error('The value of a header must be either a regular expression or a string');
}
});
}
return new Resource(data);
};
/**
* A factory method that creates a resource.
*
* @version 17.1.1
* @AbcsExtension stable
*
* @param {Object} data - An Object literal with following properties.
* @param {String} data.id - Unique ID of the created {@link bop/js/api/resource/Resource Resource}.
* @param {String} data.template - The URI template to use for this resource, will be appended to the baseUri parameter if the BOP exports {@link extensions.dt/js/api/CustomParameter CustomParameter} so naned.
* @param {String} data.entity - Unique ID of the referenced {@link entity/js/api/Entity Entity}.
* @returns {bop/js/api/resource/Resource} A new resource based on the passed in data
*
* @example
* <caption>
* Example of typical implementation a typical resource creating, providing
* the required attributes for id, template and entity id.
* </caption>
*
* var parent = Resource.create({
* id: 'employee_collection',
* template: '/employee',
* entity: 'my.custom.bop.Employee'
* });
*/
Resource.create = function (data) {
AbcsLib.checkParameterCount(arguments, 1);
Resource._validateData(data);
return Resource.createIntl(data);
};
/**
* A factory method that creates a resource relative to the parent resource.
*
* @version 17.1.1
* @AbcsExtension stable
*
* @param {bop/js/api/resource/Resource} parent The parent resource to create the resource relative to
* @param {Object} data - An Object literal with following properties.
* @param {String} data.id - Unique ID of the created {@link bop/js/api/resource/Resource Resource}.
* @param {String} data.template - The URI template to use for this resource that is appended to the template for any parent resource.
* @param {String} [data.entity] - Override the entity id of the parent resource.
* @returns {bop/js/api/resource/Resource} A new resource based on the passed in data
*
* @example
* <caption>
* Example of typical implementation a typical child resource created
* relative to a parent resource.
* </caption>
*
* var parent = Resource.create({
* id: 'employee_collection',
* template: '/employee',
* entity: 'my.custom.bop.Employee'
* });
* var child = Resource.createChild(parent, {
* id: 'employee_instance',
* template: '{id}'
* });
*/
Resource.createChild = function (parent, data) {
AbcsLib.checkParameterCount(arguments, 2);
AbcsLib.checkDefined(parent, 'parent');
AbcsLib.checkDataType(parent, Resource);
if (AbcsLib.isObject(data) && !data.entity) {
data.entity = parent.getEntityId();
}
Resource._validateData(data);
var parentTemplate = parent.getTemplate();
// No endsWith, startsWith in Node 4.5?
if (StringUtils.endsWith(parentTemplate, '/')) {
if (StringUtils.startsWith(data.template, '/')) {
data.template = parentTemplate + data.template.substring(1);
} else {
data.template = parentTemplate + data.template;
}
} else {
if (StringUtils.startsWith(data.template, '/')) {
data.template = parentTemplate + data.template;
} else {
data.template = parentTemplate + '/' + data.template;
}
}
//
data.parent_resource = parent.getId();
return Resource.createIntl(data);
};
return Resource;
});