Skip to content

Commit

Permalink
Merge
Browse files Browse the repository at this point in the history
  • Loading branch information
Jakeeyturner committed Mar 9, 2017
2 parents 1c6e402 + 454d3bc commit 7e2fccf
Show file tree
Hide file tree
Showing 40 changed files with 1,555 additions and 89 deletions.
1 change: 1 addition & 0 deletions packages/composer-client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ require('composer-common').ConnectionProfileManager.registerConnectionManagerLoa
*/

module.exports.BusinessNetworkConnection = require('./lib/businessnetworkconnection');
module.exports.TransactionRegistry = require('./lib/transactionregistry');

/**
* Expose key composer-common classes to simplify client application dependencies
Expand Down
1 change: 1 addition & 0 deletions packages/composer-common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ module.exports.BaseException = require('./lib/baseexception');
module.exports.BusinessNetworkDefinition = require('./lib/businessnetworkdefinition');
module.exports.ClassDeclaration = require('./lib/introspect/classdeclaration');
module.exports.Concept = require('./lib/model/concept');
module.exports.ConceptDeclaration = require('./lib/introspect/conceptdeclaration');
module.exports.Connection = require('./lib/connection');
module.exports.ConnectionManager = require('./lib/connectionmanager');
module.exports.ConnectionProfileManager = require('./lib/connectionprofilemanager');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ const RelationshipDeclaration = require('../../../introspect/relationshipdeclara
const TransactionDeclaration = require('../../../introspect/transactiondeclaration');
const debug = require('debug')('concerto:jsonschemavisitor');

/**
* Convert a fully qualified type name, for example org.acme.MyAsset,
* into a name that is safe for use as a LoopBack model name.
* @private
* @param {String} fqn The fully qualified type name.
* @returns {String} A name that is safe for use as a LoopBack model name.
*/
function loopbackify(fqn) {
return fqn.replace(/\./g, '_');
}

/**
* Convert the contents of a {@link ModelManager} instance to a set of LoopBack
* Definition Language model files - one per concrete asset and transaction type.
Expand Down Expand Up @@ -108,8 +119,9 @@ class LoopbackVisitor {
// Visit all of the asset and transaction declarations, but ignore the abstract ones.
let jsonSchemas = [];
modelFile.getAssetDeclarations()
.concat(modelFile.getTransactionDeclarations())
.concat(modelFile.getConceptDeclarations())
.concat(modelFile.getParticipantDeclarations())
.concat(modelFile.getTransactionDeclarations())
.filter((declaration) => {
return !declaration.isAbstract();
})
Expand All @@ -136,7 +148,7 @@ class LoopbackVisitor {
if (parameters.first) {
jsonSchema = {
$first: true,
name: assetDeclaration.getName(),
name: loopbackify(assetDeclaration.getFullyQualifiedName()),
description: `An asset named ${assetDeclaration.getName()}`,
plural: assetDeclaration.getFullyQualifiedName(),
base: 'PersistedModel',
Expand Down Expand Up @@ -178,7 +190,7 @@ class LoopbackVisitor {
if (parameters.first) {
jsonSchema = {
$first: true,
name: participantDeclaration.getName(),
name: loopbackify(participantDeclaration.getFullyQualifiedName()),
description: `A participant named ${participantDeclaration.getName()}`,
plural: participantDeclaration.getFullyQualifiedName(),
base: 'PersistedModel',
Expand Down Expand Up @@ -215,9 +227,33 @@ class LoopbackVisitor {
visitConceptDeclaration(conceptDeclaration, parameters) {
debug('entering visitConceptDeclaration', conceptDeclaration.getName());

// If this is the first declaration, then we are building a schema for this participant.
// If this is the top declaration, then we are building a schema for this concept.
let jsonSchema = {};
jsonSchema.type = 'Object';
if (parameters.first) {
jsonSchema = {
$first: true,
name: loopbackify(conceptDeclaration.getFullyQualifiedName()),
description: `A concept named ${conceptDeclaration.getName()}`,
plural: conceptDeclaration.getFullyQualifiedName(),
// Concepts are not PersistedModel instances as they cannot exist by themselves.
// base: 'PersistedModel',
idInjection: false,
options: {
validateUpsert: true,
composer: {
type: 'concept'
}
},
properties: {},
validations: [],
relations: {},
acls: [],
methods: []
};
parameters.first = false;
} else {
jsonSchema.type = 'Object';
}

// Apply all the common schema elements.
return this.visitClassDeclarationCommon(conceptDeclaration, parameters, jsonSchema);
Expand All @@ -238,7 +274,7 @@ class LoopbackVisitor {
if (parameters.first) {
jsonSchema = {
$first: true,
name: transactionDeclaration.getName(),
name: loopbackify(transactionDeclaration.getFullyQualifiedName()),
description: `A transaction named ${transactionDeclaration.getName()}`,
plural: transactionDeclaration.getFullyQualifiedName(),
base: 'PersistedModel',
Expand Down Expand Up @@ -392,11 +428,16 @@ class LoopbackVisitor {
// Not primitive, so must be a class or enumeration!
} else {

// Render the type as JSON Schema.
jsonSchema = {
type: loopbackify(field.getFullyQualifiedTypeName())
};

// Look up the type of the property.
let type = parameters.modelFile.getType(field.getType());

// Render the type as JSON Schema.
jsonSchema = type.accept(this, parameters);
// Visit it, but ignore the response.
type.accept(this, parameters);

}

Expand Down
17 changes: 17 additions & 0 deletions packages/composer-common/lib/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,23 @@ class Factory {
* @throws {ModelException} if the type is not registered with the ModelManager
*/
newResource(ns, type, id, options) {

if(!id || typeof(id) !== 'string') {
let formatter = Globalize.messageFormatter('factory-newinstance-invalididentifier');
throw new Error(formatter({
namespace: ns,
type: type
}));
}

if(id.trim().length === 0) {
let formatter = Globalize.messageFormatter('factory-newinstance-missingidentifier');
throw new Error(formatter({
namespace: ns,
type: type
}));
}

let modelFile = this.modelManager.getModelFile(ns);
if(!modelFile) {
let formatter = Globalize.messageFormatter('factory-newinstance-notregisteredwithmm');
Expand Down
20 changes: 20 additions & 0 deletions packages/composer-common/lib/serializer/resourcevalidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ class ResourceValidator {
}

if(obj instanceof Identifiable) {
const id = obj.getIdentifier();

// prevent empty identifiers
if(!id || id.trim().length === 0) {
ResourceValidator.reportEmptyIdentifier(parameters.rootResourceIdentifier);
}

this.currentIdentifier = obj.getFullyQualifiedIdentifier();
}

Expand Down Expand Up @@ -477,6 +484,19 @@ class ResourceValidator {
}));
}

/**
* Throw a new error for a missing, but required field.
* @param {string} id - the identifier of this instance.
* @param {Field} field - the field/
* @private
*/
static reportEmptyIdentifier(id) {
let formatter = Globalize.messageFormatter('resourcevalidator-emptyidentifier');
throw new ValidationException(formatter({
resourceId: id
}));
}

/**
* Throw a new error for a missing, but required field.
* @param {string} id - the identifier of this instance.
Expand Down
5 changes: 4 additions & 1 deletion packages/composer-common/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@

"factory-newinstance-notregisteredwithmm": "ModelFile for namespace {namespace} has not been registered with the ModelManager",
"factory-newinstance-typenotdeclaredinns": "Type {type} is not declared in namespace {namespace}",
"factory-newinstance-missingidentifier": "Missing identifier for Type {type} in namespace {namespace}",
"factory-newinstance-invalididentifier": "Invalid or missing identifier for Type {type} in namespace {namespace}",

"factory-newrelationship-notregisteredwithmm": "ModelFile for namespace {namespace} has not been registered with the ModelManager",
"factory-newrelationship-typenotdeclaredinns": "Type {type} is not declared in namespace {namespace}",
Expand All @@ -62,6 +64,7 @@
"resourcevalidator-invalidenumvalue": "Instance {resourceId} invalid enum value {value} for field {fieldName}",
"resourcevalidator-abstractclass": "The class {className} is abstract. Should not have an instance!",
"resourcevalidator-undeclaredfield": "Instance {resourceId} has a property named {propertyName} which is not declared in {fullyQualifiedTypeName}",
"resourcevalidator-invalidfieldassignment": "Instance {resourceId} has property {propertyName} with type {objectType} that is not derived from {fieldType}"
"resourcevalidator-invalidfieldassignment": "Instance {resourceId} has property {propertyName} with type {objectType} that is not derived from {fieldType}",
"resourcevalidator-emptyidentifier": "Instance {resourceId} has an empty identifier."
}
}
Loading

0 comments on commit 7e2fccf

Please sign in to comment.