Skip to content

Commit

Permalink
Merge branch '2.3.0' of http://10.73.97.24/oecloud.io/oe-cloud
Browse files Browse the repository at this point in the history
  • Loading branch information
vamsee committed Oct 6, 2020
2 parents c201f36 + bb05262 commit c1a05cb
Show file tree
Hide file tree
Showing 19 changed files with 762 additions and 69 deletions.
132 changes: 105 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- [oeCloud overall modules](#oecloud-overall-modules)
- [oeCloud Features and functionalities](#oecloud-features-and-functionalities)
* [oeCloud What it will do](#oecloud-what-it-will-do)
* [app-list](#app-list)
* [Usage](#usage)
* [oeCloud Models](#oecloud-models)
+ [BaseEntity](#baseentity)
Expand All @@ -17,6 +18,7 @@
* [Boot scripts](#boot-scripts)
* [Middlewares](#middlewares)
* [Model Customization](#model-customization)
* [Call context and options](#call-context-options)
- [oeCloud API Documentation](#oecloud-api-documentation)
* [Common Utility API](#common-utility-api)
+ [IsBaseEntity(Model)](#isbaseentity-model-)
Expand All @@ -39,6 +41,7 @@
* [Add fields to BaseEntity or ModelDefinition](#add-fields-to-baseentity-or-modeldefinition)
- [oeCloud Difference between old and new](#oecloud-difference-between-old-and-new)


# Introduction

oeCloud framework has been in development for almost two years and several developers for the first time worked on framework development. It has been adopted by many application developers so far and is being popular within Infosys and EdgeVerve.
Expand Down Expand Up @@ -80,21 +83,9 @@ Below are responsibilities of oe-cloud
* ensure of loading of models defined in app-list module
* expose *loopback like* APIs for application developer (eg app.boot(), app.start() etc)


## Usage

Typically, following code can be written in oeCloud application's server/server.js file

```
var oecloud = require('oe-cloud');
oecloud.boot(__dirname, function(err){
oecloud.start();
})
```

Above code should able to start application. you don't have to do require of loopback or any of it's component.
## app-list
This is basically javascript array of objects that contains list of node_modules that oe-cloud should load as part of application start up. This usually is JSON file with name as **app-list.json**. However, to achieve programmability, this can be also .js file like **app-list.js**. Another small improvement is, application developer can maintain different app-list for different environments which is based on **NODE_ENV** environment variable.
If all sources (app-list.json, app-list.js and app-list.<NODE_ENV>.js) exist, oe-cloud will merge these objects.
Typical app-list.json, which would be part of application would look like

```
Expand All @@ -111,29 +102,33 @@ Typical app-list.json, which would be part of application would look like
"path": "oe-common-mixins",
"enabled": true
},
{
"path": "oe-cache",
"enabled": true
},
{
"path": "oe-personalization",
"enabled": true
},
{
"path": "oe-validation",
"enabled": true
},
{
"path": "oe-service-personalization",
"enabled": true
},
{
"path": "./",
"enabled": true
}
]
```


## Usage

Typically, following code can be written in oeCloud application's server/server.js file

```
var oecloud = require('oe-cloud');
oecloud.boot(__dirname, function(err){
oecloud.start();
})
```

Above code should able to start application. you don't have to do require of loopback or any of it's component.

## oeCloud Models

### BaseEntity
Expand Down Expand Up @@ -255,6 +250,16 @@ In above model-config, MyModel will be created as public model. However, definit
},
```

* As said earlier, by defualt node modules mixins are not attached to BaseEntity by default. This behavior can be changed by **autoEnableMixins** for node module. See example below of app-list.json

```javaScript
"OeSomeModule" : {
"enable" : true,
"autoEnableMixins" : true
}
```
above setting will ensure that all mixins of OeSomeModule are attahced to BaseEntity and therefore attach to all models derived from BaseEntity.

* you can also selectively ON/OFF the mixin attachments by calling **addModuleMixinsToBaseEntity** API as below. This can be important if you have to have some mixins from other dependent module.

```
Expand Down Expand Up @@ -379,6 +384,76 @@ You can also have customer.js file which is then loaded and also you can have mi
**Note** : More importantly exports function all .js files of models are executed in sequence. There should not be any extra executable code apart from that inside module.exports () function.
## Call Context and options
### Options
When we are referring to options, we are referring to second parameter usually we pass to model.find() or model.create() functions. This options parameter flows throughout the loopback pipeline. That is all observer hooks will get context in which it has this options parameter.
```
model.find({where : {id : "a"}}, {ctx : {somefield : "X"} }, function(err, data){
// results are returned in data
});
model.observe('access', function(ctx, next){
assert(ctx.options.somefield === 'X')
})
```
This is all good when find() is being called by programmer from javascript code. However when find() is called due to http GET request on model, options parameter is parepared in oe-cloud module. specifically lib/warpper.js's _newCreateOptionsFromRemotingContext() is used to build this options.
options has got most important property **ctx**. All other properties are not touched by oecloud framework.
This property is now built by http request's callContext.ctx property and basically both are actually same.
therefore if the request object is req and options object is options then
```
assert(req.callContext.ctx === options.ctx);
```
With above design, if you change callContext.ctx property in middleware, that will be directly reflected in options.ctx property
### callContext
callContext property of HTTP request is created by oeCloud framework in one of it's middleware. As said above callContext.ctx is same as options.ctx. you must break this link. With this link if you modify callContext.ctx in **middleware** or **before remote** hooks, it will be available in options.ctx field in your **observer hooks**.
Same way, if you change options.ctx in observer hooks, you will see that in **after remote** hook.
```
model.beforeRemote( '**', function( ctx, opts, next) {
ctx.req.callContext.someField = 'x';
next();
});
model.observe('before save', function(ctx, next){
assert(ctx.options.ctx.someField === 'x');
ctx.options.ctx.otherField = 'y'
// never do this as it will break link ---->>> ctx.options.ctx = { otherField : 'y', someField : 'x' }
});
model.afterRemote( '**', function( ctx, opts, next) {
assert(ctx.options.ctx.otherField === 'y');
next();
});
```
# oeCloud API Documentation
## Common Utility API
Expand Down Expand Up @@ -646,3 +721,6 @@ app.observe('loaded', function(ctx, next){
| Service Personalization | Mixin+Boot | Boot [oe-service=personalization](https://github.com/EdgeVerve/oe-service-personalization) |
| Cachinge | Mixin+DAO | DAO Wrapper [oe-cache](https://github.com/EdgeVerve/oe-cache) |
4 changes: 4 additions & 0 deletions common/models/error.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
"type": "string",
"max": 250
},
"errCategory": {
"type": "string",
"max": 100
},
"moreInformation": {
"type": "string",
"max": 500
Expand Down
8 changes: 5 additions & 3 deletions lib/common/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,16 @@ function getIdValue(m, data) {
}

const BASE_ENTITY = 'BaseEntity';
const PERSISTED_MODEL = 'PersistedModel';
const BASE_MODEL = 'Model';
// utility function to climb up inheritance tree
// and execute callback on each hit. This will hit
// all models except BaseEntity
// all models except BaseEntity, PersistedModel and Model
const inheritanceTraverse = function (model, ctx, cb) {
if (model.base.modelName !== BASE_ENTITY && cb(model.base)) {
if (model && model.base && model.base.modelName !== BASE_ENTITY && model.base.modelName !== PERSISTED_MODEL && model.base.modelName !== BASE_MODEL && cb(model.base)) {
// do nothing
return;
} else if (model.base.modelName === BASE_ENTITY) {
} else if (model && model.base && (model.base.modelName === BASE_ENTITY || model.base.modelName === PERSISTED_MODEL || model.base.modelName === BASE_MODEL)) {
return;
}

Expand Down
14 changes: 11 additions & 3 deletions lib/error-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* This class acts as an error wrapper which customises the loopback error by adding customised messages to it.
* It prepares an customised error object which is finally attached to the response object.
* @module ErrorUtils
* @author Pragyan Das
* @author Pragyan Das and Dipayan Aich
*/

var logger = require('oe-logger');
Expand Down Expand Up @@ -123,7 +123,7 @@ function attachValidationError(instance, errArr) {
});
}
errArr.forEach(function modelValidationsGetErrorForEachFn(err) {
instance.errors.add(err.fieldName, err.errMessage, err.errCode, err.errCategory ? err.errCategory : '');
instance.errors.add(err.fieldName, err.errMessage, err.errCode, err.errCategory ? err.errCategory : null, err.path);
});
}

Expand All @@ -140,7 +140,7 @@ function Errors() {
});
}

Errors.prototype.add = function (field, message, code, category) {
Errors.prototype.add = function (field, message, code, category, path) {
code = code || 'invalid';
if (!this[field]) {
this[field] = [];
Expand All @@ -152,6 +152,14 @@ Errors.prototype.add = function (field, message, code, category) {
if (category) {
this.category[field].push(category);
}

if (!this.fieldPaths) {
this.fieldPaths = {};
}
if (!this.fieldPaths[field]) {
this.fieldPaths[field] = [];
}
this.fieldPaths[field].push(path);
};

var getErrorDetails = function getErrorDetails() {
Expand Down
71 changes: 55 additions & 16 deletions lib/load.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,44 @@ function getRootFolder() {
return rootFolder;
}

function initAppList() {
// var options = {};
var rootFolder = getRootFolder();
var a1; var a2; var a3;
if (fs.existsSync(rootFolder + '/app-list.json')) {
a1 = require(rootFolder + '/app-list.json');
}
if (fs.existsSync(rootFolder + '/app-list.js')) {
a2 = require(rootFolder + '/app-list.js');
}
if (process.env.NODE_ENV) {
if (fs.existsSync(rootFolder + '/app-list.' + process.env.NODE_ENV + '.js')) {
a3 = require(rootFolder + '/app-list.' + process.env.NODE_ENV + '.js');
}
}


var applist = Object.assign({}, a1, a2, a3);
applist = Object.values(applist);

// var applist = require(rootFolder + '/app-list.json');
// options = mergeUtil.loadAppList(applist, rootFolder, options);
// options.bootDirs.push(path.join(rootFolder, 'boot'));
// options.clientAppRootDir = rootFolder;
app.applist = applist;
app.appHome = rootFolder;
// return options;
}

function createMergedOptions() {
var options = {};
var rootFolder = getRootFolder();
var applist = require(rootFolder + '/app-list.json');
var rootFolder = app.appHome;
var applist = app.applist;
options = mergeUtil.loadAppList(applist, rootFolder, options);
options.bootDirs.push(path.join(rootFolder, 'boot'));
options.clientAppRootDir = rootFolder;
app.applist = applist;
app.appHome = rootFolder;
// app.applist = applist;
// app.appHome = rootFolder;
return options;
}

Expand Down Expand Up @@ -155,18 +184,28 @@ function appboot(app, options, callback) {
});
}


// Atul : rearrange creation of server and notifying programmer before creating merge options
// programmer can manipulate app-list
app.boot = function (options, cb) {
loadOeModules(app, (err) => {
app.createServer();
app.notifyObserversOf('before-boot-options-prepared', {}, (err) => {
if (err) {
return cb(new Error('Error in loadingOeModules ' + err));
}
var cookieSecret = app.get('cookieSecret');
if (!cookieSecret) {
app.set('cookieSecret', 'oe-cloud-secret');
cookieSecret = app.get('cookieSecret');
}
appboot(app, app.options, (err) => {
return cb(err);
}
app.options = createMergedOptions();
loadOeModules(app, (err) => {
if (err) {
return cb(new Error('Error in loadingOeModules ' + err));
}
var cookieSecret = app.get('cookieSecret');
if (!cookieSecret) {
app.set('cookieSecret', 'oe-cloud-secret');
cookieSecret = app.get('cookieSecret');
}
appboot(app, app.options, (err) => {
return cb(err);
});
});
});

Expand All @@ -188,9 +227,9 @@ app.start = function () {
});
};

app.createServer();
app.options = createMergedOptions();

// app.createServer();
// app.options = createMergedOptions();
initAppList();

function loadOeModules(app, cb) {
mixinUtil.loadMixins();
Expand Down
Loading

0 comments on commit c1a05cb

Please sign in to comment.