/** * Get all of the resources in the registry, and resolve all of their relationships * to other assets, participants, and transactions. The result is a JavaScript * object, and should only be used for visualization purposes. You cannot use * the {@link #add add} or {@link #update update} functions with a resolved resource. * * @return {Promise} A promise that will be resolved with an array of JavaScript * objects representing the resources and all of their resolved relationships. */ resolveAll() { Util.securityCheck(this.securityContext); return Util.queryChainCode(this.securityContext, 'resolveAllResourcesInRegistry', [this.registryType, this.id]) .then((buffer) => { return JSON.parse(buffer.toString()); }); }
/** * Updates a resource in the registry. * * @param {Resource} resource The resource to be updated in the registry. * @return {Promise} A promise that will be resolved when the resource is * updated in the registry. */ update(resource) { Util.securityCheck(this.securityContext); if (!resource) { throw new Error('resource not specified'); } let serializedResource = this.serializer.toJSON(resource); return Util.invokeChainCode(this.securityContext, 'updateResourceInRegistry', [this.registryType, this.id, JSON.stringify(serializedResource)]); }
/** * Execute a query against all resources in the registry. The JSONata * expression is applied to each resource in the registry, and the result * of the JSONata expression is returned if the result is truthy. The result * is a JavaScript object, and should only be used for visualization * purposes. You cannot use the {@link add} or {@link update} functions with * data returned by this function. * * @param {string} expression The JSONata expression. * @return {Promise} A promise that will be resolved with an array of JavaScript * objects representing the resources and all of their resolved relationships. */ query(expression) { Util.securityCheck(this.securityContext); if (!expression) { throw new Error('expression not specified'); } return Util.queryChainCode(this.securityContext, 'queryResourcesInRegistry', [this.registryType, this.id, expression]) .then((buffer) => { return JSON.parse(buffer.toString()); }); }
/** * Get a list of all existing registries. * * @protected * @param {SecurityContext} securityContext The user's security context. * @param {string} registryType The type of this registry. * @return {Promise} A promise that will be resolved with an array of JSON * objects representing the registries. */ static getAllRegistries(securityContext, registryType) { Util.securityCheck(securityContext); if (!registryType) { throw new Error('registryType not specified'); } return Util.queryChainCode(securityContext, 'getAllRegistries', [registryType]) .then((buffer) => { return JSON.parse(buffer.toString()); }); }
/** * Get a specific resource in the registry, and resolve all of its relationships * to other assets, participants, and transactions. The result is a JavaScript * object, and should only be used for visualization purposes. You cannot use * the {@link #add add} or {@link #update update} functions with a resolved resource. * * @param {string} id The unique identifier of the asset. * @return {Promise} A promise that will be resolved with a JavaScript object * representing the resource and all of its resolved relationships. */ resolve(id) { Util.securityCheck(this.securityContext); if (!id) { throw new Error('id not specified'); } return Util.queryChainCode(this.securityContext, 'resolveResourceInRegistry', [this.registryType, this.id, id]) .then((buffer) => { return JSON.parse(buffer.toString()); }); }
/** * Updates a list of resources in the registry. * * @param {Resource[]} resources The resources to be updated in the asset registry. * @return {Promise} A promise that will be resolved when the resource is * added to the registry. */ updateAll(resources) { Util.securityCheck(this.securityContext); if (!resources) { throw new Error('resources not specified'); } let serializedResources = resources.map((resource) => { return this.serializer.toJSON(resource); }); return Util.invokeChainCode(this.securityContext, 'updateAllResourcesInRegistry', [this.registryType, this.id, JSON.stringify(serializedResources)]); }
/** * Determines whether a registry exists. * * @protected * @param {SecurityContext} securityContext The user's security context. * @param {string} registryType The type of this registry. * @param {string} id The unique identifier of the registry. * @return {Promise} A promise that will be resolved with true/false depending on whether the registry exists */ static existsRegistry(securityContext, registryType, id) { Util.securityCheck(securityContext); if (!registryType) { throw new Error('registryType not specified'); } else if (!id) { throw new Error('id not specified'); } return Util.queryChainCode(securityContext, 'existsRegistry', [registryType, id]) .then((buffer) => { return JSON.parse(buffer.toString()); }); }
/** * Get all of the resources in the registry. * * @return {Promise} A promise that will be resolved with an array of JSON * objects representing the resources. */ getAll() { Util.securityCheck(this.securityContext); return Util.queryChainCode(this.securityContext, 'getAllResourcesInRegistry', [this.registryType, this.id]) .then((buffer) => { return JSON.parse(buffer.toString()); }) .then((resources) => { return resources.map((resource) => { return this.serializer.fromJSON(resource); }); }); }
/** * Remove an asset with a given type and id from the registry. * * @param {(Resource|string)} resource The resource, or the unique identifier of the resource. * @return {Promise} A promise that will be resolved when the resource is * removed from the registry. */ remove(resource) { Util.securityCheck(this.securityContext); if (!resource) { throw new Error('resource not specified'); } let id; if (resource instanceof Resource) { id = resource.getIdentifier(); } else { id = resource; } return Util.invokeChainCode(this.securityContext, 'removeResourceFromRegistry', [this.registryType, this.id, id]); }
/** * Revoke the specified identity by removing any existing mapping to a participant. * @param {string} identity The identity, for example the enrollment ID. * @return {Promise} A promise that will be fulfilled when the identity has * been removed from the specified participant. The promise will be rejected if * the participant does not exist, or if the identity is not mapped to the * participant. */ revokeIdentity(identity) { const method = 'revokeIdentity'; LOG.entry(method, identity); if (!identity) { throw new Error('identity not specified'); } Util.securityCheck(this.securityContext); // It is not currently possible to revoke the certificate, so we just call // the runtime to remove the mapping. return Util.invokeChainCode(this.securityContext, 'removeIdentity', [identity]) .then(() => { LOG.exit(method); }); }
/** * Removes a list of resources from the registry. * * @param {(Resource[]|string[])} resources The resources, or the unique identifiers of the resources. * @return {Promise} A promise that will be resolved when the resource is * added to the registry. */ removeAll(resources) { Util.securityCheck(this.securityContext); if (!resources) { throw new Error('resources not specified'); } let data = resources.map((resource) => { if (resource instanceof Resource) { return resource.getIdentifier(); } else { return resource; } }); return Util.invokeChainCode(this.securityContext, 'removeAllResourcesFromRegistry', [this.registryType, this.id, JSON.stringify(data)]); }
.then((identity) => { return Util.invokeChainCode(this.securityContext, 'addParticipantIdentity', [participantFQI, userID]) .then(() => { LOG.exit(method, identity); return identity; }); });
/** * Remove an asset with a given type and id from the registry. * * @param {(Resource|string)} resource The resource, or the unique identifier of the resource. * @return {Promise} A promise that will be resolved when the resource is * removed from the registry. */ remove(resource) { Util.securityCheck(this.securityContext); if (!resource) { throw new Error('resource not specified'); } return this.removeAll([resource]); }
/** * Execute a query defined in a Composer query file, or execute a query built with buildQuery. * * This functionality is Blockchain platform dependent. For example, when a Composer * business network is deployed to Hyperledger Fabric v1.0, Hyperledger Fabric must be * configured with the CouchDB database for the world state. * @example * // Execute the query. * var businessNetwork = new BusinessNetworkConnection(); * return businessNetwork.connect('testprofile', 'businessNetworkIdentifier', 'WebAppAdmin', 'DJY27pEnl16d') * .then(function () { * return query('Q1', { inputValue: 'blue' }) * }) * .then(function (assets) { * assets.forEach(function (asset) { * // Process each asset. * }); * }) * .catch(function (error) { * // Add optional error handling here. * }); * @param {string|Query} query The name of the query, or a built query. * @param {Object} [parameters] The parameters for the query. * @return {Promise} A promise that will be resolved with an array of * {@link module:composer-common.Resource Resource} representing the * resources returned by the query. */ query(query, parameters) { const method = 'query'; LOG.entry(method, query, parameters); let queryType, identifier; if (query instanceof Query) { queryType = 'build'; identifier = query.getIdentifier(); } else if (typeof query === 'string') { queryType = 'named'; identifier = query; } else { throw new Error('Invalid query; expecting a built query or the name of a query'); } parameters = parameters || {}; return Util.queryChainCode(this.securityContext, 'executeQuery', [queryType, identifier, JSON.stringify(parameters)]) .then((buffer) => { return JSON.parse(buffer.toString()); }) .then((resources) => { const result = resources.map((resource) => { return this.getBusinessNetwork().getSerializer().fromJSON(resource); }); LOG.exit(method, result); return result; }); }
/** * Internal method to check the security context * @param {SecurityContext} securityContext - The user's security context * @throws {SecurityException} if the user context is invalid */ static securityCheck(securityContext) { if (Util.isNull(securityContext)) { throw new SecurityException(Globalize.formatMessage('util-securitycheck-novalidcontext')); } else if (!(securityContext instanceof HFCSecurityContext)) { throw new SecurityException(Globalize.formatMessage('util-securitycheck-novalidcontext')); } }
/** * Add a new asset registry. * * @protected * @param {SecurityContext} securityContext The user's security context. * @param {string} registryType The type of this registry. * @param {string} id The unique identifier of the registry. * @param {string} name The name of the registry. * @return {Promise} A promise that will be resolved with a JSON object * representing the registry. */ static addRegistry(securityContext, registryType, id, name) { Util.securityCheck(securityContext); if (!registryType) { throw new Error('registryType not specified'); } else if (!id) { throw new Error('id not specified'); } else if (!name) { throw new Error('name not specified'); } return Util.invokeChainCode(securityContext, 'addRegistry', [registryType, id, name]) .then(() => { return { id: id, name: name }; }); }
/** * Reset the business network to its initial state. * @return {Promise} - a promise that will be resolved when complete. */ static resetBusinessNetwork() { if (!client) { return Promise.resolve(); } // TODO: hack hack hack, this should be in the admin API. let securityContext = client.securityContext; if (!securityContext) { return Promise.resolve(); } return Util.invokeChainCode(client.securityContext, 'resetBusinessNetwork', []); }
/** * Invoke a "invoke" chaincode function with the specified name and arguments. * @param {SecurityContext} securityContext The participant's security context. * @param {string} functionName The name of the chaincode function to invoke. * @param {string[]} args The arguments to pass to the chaincode function. * @param {Object} [additionalConnectorOptions] Additional connector specific options for this transaction. * @return {Buffer} A buffer containing the data returned by the chaincode function, * or null if no data was returned. */ async invokeChainCode(securityContext, functionName, args, additionalConnectorOptions = {}) { if (!this.businessNetworkIdentifier) { throw new Error('No business network has been specified for this connection'); } let identity = securityContext.getIdentity(); let chaincodeUUID = securityContext.getChaincodeID(); let chaincode = EmbeddedConnection.getChaincode(chaincodeUUID); let context = new EmbeddedContext(chaincode.engine, identity, this, chaincode.installedBusinessNetwork, additionalConnectorOptions); const data = await chaincode.engine.invoke(context, functionName, args); return !Util.isNull(data) ? Buffer.from(JSON.stringify(data)) : null; }
/** * Get the transaction registry. * @example * // Get the transaction registry * var businessNetwork = new BusinessNetworkConnection(); * return businessNetwork.connect('testprofile', 'businessNetworkIdentifier', 'WebAppAdmin', 'DJY27pEnl16d') * .then(function(businessNetworkDefinition){ * return businessNetworkDefinition.getTransactionRegistry(); * }) * .then(function(transactionRegistry){ * // Retrieved Transaction Registry * }); * @return {Promise} - A promise that will be resolved to the {@link TransactionRegistry} */ getTransactionRegistry() { Util.securityCheck(this.securityContext); return TransactionRegistry .getAllTransactionRegistries(this.securityContext, this.getBusinessNetwork().getModelManager(), this.getBusinessNetwork().getFactory(), this.getBusinessNetwork().getSerializer()) .then((transactionRegistries) => { if (transactionRegistries.length >= 1) { return transactionRegistries[0]; } else { throw new Error('Failed to find the default transaction registry'); } }); }
/** * Updates a list of resources in the registry. * * @param {Resource[]} resources The resources to be updated in the asset registry. * @return {Promise} A promise that will be resolved when the resource is * added to the registry. */ updateAll(resources) { Util.securityCheck(this.securityContext); if (!resources) { throw new Error('resources not specified'); } let txName = 'Update'+this.registryType; const transaction = this.factory.newTransaction('org.hyperledger.composer.system',txName); // target registry is the registry that this the client 'shadow' of transaction.targetRegistry = this.factory.newRelationship('org.hyperledger.composer.system',this.registryType+'Registry', this.id); transaction.resources = resources; return this.bnc.submitTransaction(transaction); }
/** * Updates a list of resources in the registry. * * @param {Resource[]} resources The resources to be updated in the asset registry. * @return {Promise} A promise that will be resolved when the resource is * added to the registry. */ updateAll(resources) { Util.securityCheck(this.securityContext); if (!resources) { throw new Error('resources not specified'); } let txName = 'Update'+this.registryType; const transaction = this.factory.newTransaction('org.hyperledger.composer.system',txName); transaction.resources = resources; transaction.registryType = this.registryType; transaction.registryId = this.id; return this.bnc.submitTransaction(transaction); }
/** * Determine whether a participant registry exists. * * @protected * @param {SecurityContext} securityContext The user's security context. * @param {string} id The unique identifier of the asset registry. * @param {ModelManager} modelManager The ModelManager to use for this asset registry. * @param {Factory} factory The factory to use for this asset registry. * @param {Serializer} serializer The Serializer to use for this asset registry. * @param {BusinessNetworkConnection} bnc BusinessNetworkConnection to use * @return {Promise} A promise that will be resolved with a boolean indicating whether the asset registry exists */ static participantRegistryExists(securityContext, id, modelManager, factory, serializer, bnc) { Util.securityCheck(securityContext); if (!id) { throw new Error('id not specified'); } else if (!modelManager) { throw new Error('modelManager not specified'); } else if (!factory) { throw new Error('factory not specified'); } else if (!serializer) { throw new Error('serializer not specified'); } return Registry.existsRegistry(securityContext, REGISTRY_TYPE, id); }
/** * Adds a list of new resources to the registry. * * @param {Resource[]} resources The resources to be added to the registry. * @return {Promise} A promise that will be resolved when the resource is * added to the registry. */ addAll(resources) { Util.securityCheck(this.securityContext); if (!resources) { throw new Error('resources not specified'); } let txName = 'Add'+this.registryType; const transaction = this.factory.newTransaction('org.hyperledger.composer.system',txName); // This code is retained as there was a suggesstion that the transaction should include // a relationship to the registry not the type/id. Time ran out to get this implemented // transaction.targetRegistry = this.factory.newRelationship(ModelUtil.getNamespace(this.id),this.registryType, this.id); transaction.registryType = this.registryType; transaction.registryId = this.id; transaction.resources = resources; return this.bnc.submitTransaction(transaction); }
/** * Get an existing participant registry. * * @protected * @param {SecurityContext} securityContext The user's security context. * @param {string} id The unique identifier of the participant registry. * @param {ModelManager} modelManager The ModelManager to use for this participant registry. * @param {Factory} factory The factory to use for this participant registry. * @param {Serializer} serializer The Serializer to use for this participant registry. * @param {BusinessNetworkConnection} bnc BusinessNetworkConnection to use * @return {Promise} A promise that will be resolved with a {@link ParticipantRegistry} * instance representing the participant registry. */ static getParticipantRegistry(securityContext, id, modelManager, factory, serializer, bnc) { Util.securityCheck(securityContext); if (!id) { throw new Error('id not specified'); } else if (!modelManager) { throw new Error('modelManager not specified'); } else if (!factory) { throw new Error('factory not specified'); } else if (!serializer) { throw new Error('serializer not specified'); } return Registry.getRegistry(securityContext, REGISTRY_TYPE, id) .then((registry) => { return new ParticipantRegistry(registry.id, registry.name, securityContext, modelManager, factory, serializer, bnc); }); }
/** * Get a list of all existing participant registries. * * @protected * @param {SecurityContext} securityContext The user's security context. * @param {ModelManager} modelManager The ModelManager to use for this participant registry. * @param {Factory} factory The factory to use for this participant registry. * @param {Serializer} serializer The Serializer to use for this participant registry. * @param {BusinessNetworkConnection} bnc BusinessNetworkConnection to use * @param {Boolean} [includeSystem] Should system registries be included? (optional, default to false) * @return {Promise} A promise that will be resolved with a list of {@link ParticipantRegistry} * instances representing the participant registries. */ static getAllParticipantRegistries(securityContext, modelManager, factory, serializer, bnc, includeSystem) { Util.securityCheck(securityContext); if (!modelManager) { throw new Error('modelManager not specified'); } else if (!factory) { throw new Error('factory not specified'); } else if (!serializer) { throw new Error('serializer not specified'); } return Registry.getAllRegistries(securityContext, REGISTRY_TYPE,includeSystem) .then((participantRegistries) => { return participantRegistries.map((participantRegistry) => { return new ParticipantRegistry(participantRegistry.id, participantRegistry.name, securityContext, modelManager, factory, serializer, bnc); }); }); }
/** * Get a list of all existing asset registries. * * @protected * @param {SecurityContext} securityContext The user's security context. * @param {ModelManager} modelManager The ModelManager to use for this asset registry. * @param {Factory} factory The factory to use for this asset registry. * @param {Serializer} serializer The Serializer to use for this asset registry. * @return {Promise} A promise that will be resolved with a list of {@link AssetRegistry} * instances representing the asset registries. */ static getAllAssetRegistries(securityContext, modelManager, factory, serializer) { Util.securityCheck(securityContext); if (!modelManager) { throw new Error('modelManager not specified'); } else if (!factory) { throw new Error('factory not specified'); } else if (!serializer) { throw new Error('serializer not specified'); } return Registry.getAllRegistries(securityContext, REGISTRY_TYPE) .then((assetRegistries) => { return assetRegistries.map((assetRegistry) => { return new AssetRegistry(assetRegistry.id, assetRegistry.name, securityContext, modelManager, factory, serializer); }); }); }
/** * Add a new asset registry. * * @protected * @param {SecurityContext} securityContext The user's security context. * @param {string} id The unique identifier of the asset registry. * @param {string} name The name of the asset registry. * @param {ModelManager} modelManager The ModelManager to use for this asset registry. * @param {Factory} factory The factory to use for this asset registry. * @param {Serializer} serializer The Serializer to use for this asset registry. * @return {Promise} A promise that will be resolved with a {@link AssetRegistry} * instance representing the new asset registry. */ static addAssetRegistry(securityContext, id, name, modelManager, factory, serializer) { Util.securityCheck(securityContext); if (!id) { throw new Error('id not specified'); } else if (!name) { throw new Error('name not specified'); } else if (!modelManager) { throw new Error('modelManager not specified'); } else if (!factory) { throw new Error('factory not specified'); } else if (!serializer) { throw new Error('serializer not specified'); } return Registry.addRegistry(securityContext, REGISTRY_TYPE, id, name) .then(() => { return new AssetRegistry(id, name, securityContext, modelManager, factory, serializer); }); }
/** * Removes a list of resources from the registry. * * @param {(Resource[]|string[])} resources The resources, or the unique identifiers of the resources. * @return {Promise} A promise that will be resolved when the resource is * added to the registry. */ removeAll(resources) { Util.securityCheck(this.securityContext); if (!resources) { throw new Error('resources not specified'); } let txName = 'Remove'+this.registryType; const transaction = this.factory.newTransaction('org.hyperledger.composer.system',txName); transaction.resources = []; transaction.registryType = this.registryType; transaction.registryId = this.id; transaction.resourceIds = resources.map((resource) => { if (resource instanceof Resource) { return resource.getIdentifier(); } else { return resource; } }); return this.bnc.submitTransaction(transaction); }
/** * Removes a list of resources from the registry. * * @param {(Resource[]|string[])} resources The resources, or the unique identifiers of the resources. * @return {Promise} A promise that will be resolved when the resource is * added to the registry. */ removeAll(resources) { Util.securityCheck(this.securityContext); if (!resources) { throw new Error('resources not specified'); } let txName = 'Remove'+this.registryType; const transaction = this.factory.newTransaction('org.hyperledger.composer.system',txName); transaction.resources = []; // target registry is the registry that this the client 'shadow' of transaction.targetRegistry = this.factory.newRelationship('org.hyperledger.composer.system',this.registryType+'Registry', this.id); transaction.resourceIds = resources.map((resource) => { if (resource instanceof Resource) { return resource.getIdentifier(); } else { return resource; } }); return this.bnc.submitTransaction(transaction); }
/** * Issue an identity with the specified user ID and map it to the specified * participant. * @param {Resource|string} participant The participant, or the fully qualified * identifier of the participant. The participant must already exist. * @param {string} userID The user ID for the identity. * @param {object} [options] Options for the new identity. * @param {boolean} [options.issuer] Whether or not the new identity should have * permissions to create additional new identities. False by default. * @return {Promise} A promise that will be fulfilled when the identity has * been added to the specified participant. The promise will be rejected if * the participant does not exist, or if the identity is already mapped to * another participant. */ issueIdentity(participant, userID, options) { const method = 'issueIdentity'; LOG.entry(method, participant, userID); if (!participant) { throw new Error('participant not specified'); } else if (!userID) { throw new Error('userID not specified'); } let participantFQI; if (participant instanceof Resource) { participantFQI = participant.getFullyQualifiedIdentifier(); } else { participantFQI = participant; } Util.securityCheck(this.securityContext); return this.connection.createIdentity(this.securityContext, userID, options) .then((identity) => { return Util.invokeChainCode(this.securityContext, 'addParticipantIdentity', [participantFQI, userID]) .then(() => { LOG.exit(method, identity); return identity; }); }); }