I want to build a medicine-network in hyperledger composer playground online.
I have created one cto file and one js file for that. I am new to this blockchain and want to create a business network for tracking a secure box. here participants are:- customer, Manufacturer, transport company
Asset- order,Securebox,beauty products in the securebox
I am unable to get the results for the placeorder event.
I posted the file which I have created
securebox.cto
/**
* securebox tracking
*/
namespace org.acme.securebox
/**
* The types of BOX that could be moved
*/
enum BoxType {
o SecureBox
o NORMALBOX
o OTHERS
}
/**
* Status of an order
*/
enum OrderStatus {
o ORDER_PLACED
o IN_FIELD
o IN_TRANSIT
o DELIVERED
}
/**
* The production type associated with a Box
*/
enum ProductionType {
o SUGAR_MEDICINE
o BLOODPRESSURE_MEDICINE
o OTHER
}
/**
* The Lock status associated with a Box
*/
enum BoxStatusType {
o LOCK
o UNLOCK
}
/**
* A Person participant
*/
abstract participant User identified by email {
o String email
o String firstName
o String lastName
}
participant Customer identified by custId extends User {
o String custId
o String address1 optional
o String address2 optional
o String county optional
}
/**
* A manufacturer of medicine
*/
participant Manufacturer identified by companyName {
o String companyName
}
/**
* An order for a medicine/others to be fulfilled by a manufacturer
* and dispatched to an orderer (Person).
*/
asset Order identified by orderId {
o String orderId
o ProductionType productiontype
o OrderStatus orderStatus
--> Customer customer
--> Manufacturer manufacturer
}
/**
* An Medicine asset, which is related to a order
*/
asset Medicine identified by medicineName {
o String medicineName
o BoxType box
o OrderStatus movementStatus
o ProductionType productionType
--> Manufacturer owner
}
/**
* An order for a medicine/others to be fulfilled by a manufacturer
* and dispatched to an orderer (Person).
*/
asset SecureBox identified by secureBoxId {
o String secureBoxId
o BoxStatusType statustype
}
/**
* Transaction to create an order
*/
transaction PlaceOrder {
o String orderId
--> Customer customer
--> Manufacturer manufacturer
}
event PlaceOrderEvent {
o String orderId
}
securebox.js
'use strict';
/**
*
* #param {org.acme.securebox.PlaceOrder} placeOrder - the placeOrder transaction
* #transaction
*/
function PlaceOrder(placeOrder) {
console.log('placeOrder');
var factory = getFactory();
var NS_M = 'org.acme.securebox';
var NS = 'org.acme';
var order = factory.newResource(NS_M, 'Order', placeOrder.orderId);
order.productiontype = 'SUGAR_MEDICINE';
order.orderStatus = 'ORDER_PLACED';
order.manufacturer = placeOrder.manufacturer;
// save the order
return getAssetRegistry(order.getFullyQualifiedType())
.then(function (registry) {
return registry.add(order);
})
.then(function(){
var placeOrderEvent = factory.newEvent(NS_M, 'PlaceOrderEvent');
placeOrderEvent.orderId = order.orderId;
emit(placeOrderEvent);
});
}
while submit the transaction, I am unable to get the output as expected.
Getting the error # Instance org.acme.securebox.Order#1234 missing required field customer
Please help me out this
You are missing one sentence in securebox.js in PlaceOrder() function:
just add one line there:
order.customer = placeOrder.customer;
Related
I have a Customer node class like this:
#Node
public class Customer extends BaseGraphEntity {
private int customerId;
private String name;
private double size;
#Relationship(type = "TRAN",direction = Relationship.Direction.OUTGOING)
public Set<Transaction> transactions;
public void inTran(Customer target, int year, double amount) {
if (transactions == null) {
transactions = new HashSet<>();
}
transactions.add(new Transaction().withAmount(amount).withTarget(target).withYear(year));
}
}
And a relationship entity Transaction as:
#RelationshipProperties
public class Transaction extends BaseGraphEntity {
private double amount;
private int year;
#TargetNode
private Customer target;
}
This is my repository method:
public interface GraphRepository extends Neo4jRepository<Customer, Long>{
#Query("MATCH (o:Customer{customerId: $customerId})-[t:TRAN]->(c) where t.year = $year return o,t,c")
Customer getRelationsOfACustomer(int customerId, int year);
}
I checked the query using neo4j client and it returns what I want as shown in image(C1 is main customer):
However, I want to cast this result in a singe Customer node with 2 elements in its "transactions" set and I want to keep all properties of Transaction class in the elements of set. But when I run it asks me to convert result into list of customers and when I do I lost transaction properties.
Is it possible to store result in single Customer instance with transactions? If so, how can I do this? I am open for all suggestions. Thanks for any help.
I have a scenario where i need to use different mono which could return me errors and set map values to null if error is returned.
Ex:
Mono<A> a=Some api call;
Mono<A> b=Some api giving error;
Mono<A> c=Some api call;
Now i want to set the resulting response to map
Map<String,A> m=new HashMap<>();
m.put("a",a);
m.put("b",null);
m.put("c",c);
Can anyone help on how to do all this in reactive non blocking way.
I tried zip but it will not execute if any of the api return error or if i use onErrorReturn(null).
Thanks in advance
To solve your problems, you will have to use some tricks. The problem is that :
Giving an empty mono or mono that ends in error cancel zip operation (source: Mono#zip javadoc)
Reactive streams do not allow null values (source: Reactive stream spec, table 2: Subscribers, bullet 13)
Also, note that putting a null value in a hash map is the same as cancelling any previous value associated with the key (it's important in case you're updating an existing map).
Now, to bypass your problem, you can add an abstraction layer, and wrap your values in domain objects.
You can have an object that represents a query, another a valid result, and the last one will mirror an error.
With that, you can design publishers that will always succeed with non null values.
That's a technic used a lot in functional programming : common errors are part of the (one possible) result value.
Now, let's see the example that create a new Map from multiple Monos:
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;
import java.util.Map;
public class BypassMonoError {
/**
* An object identified by a key. It serves to track which key to associate to computed values
* #param <K> Type of the key
*/
static class Identified<K> {
protected final K id;
Identified(K id) {
this.id = id;
}
public K getId() {
return id;
}
}
/**
* Describe the result value of an operation, along with the key associated to it.
*
* #param <K> Type of the identifier of the result
* #param <V> Value type
*/
static abstract class Result<K, V> extends Identified<K> {
Result(K id) {
super(id);
}
/**
*
* #return Computed value on success, or null if the operation has failed. Note that here, we cannot tell from
* a success returning a null value or an error
*/
abstract V getOrNull();
}
static final class Success<K, V> extends Result<K, V> {
private final V value;
Success(K id, V value) {
super(id);
this.value = value;
}
#Override
V getOrNull() {
return value;
}
}
static final class Error<K, V> extends Result<K, V> {
private final Exception error;
Error(K id, Exception error) {
super(id);
this.error = error;
}
#Override
V getOrNull() {
return null;
}
public Exception getError() {
return error;
}
}
/**
* A request that can asynchronously generate a result for the associated identifier.
*/
static class Query<K, V> extends Identified<K> {
private final Mono<V> worker;
Query(K id, Mono<V> worker) {
super(id);
this.worker = worker;
}
/**
* #return The operator that computes the result value. Note that any error is silently wrapped in an
* {#link Error empty result with error metadata}.
*/
public Mono<Result<K, V>> runCatching() {
return worker.<Result<K, V>>map(success -> new Success<>(id, success))
.onErrorResume(Exception.class, error -> Mono.just(new Error<K, V>(id, error)));
}
}
public static void main(String[] args) {
final Flux<Query<String, String>> queries = Flux.just(
new Query("a", Mono.just("A")),
new Query("b", Mono.error(new Exception("B"))),
new Query("c", Mono.delay(Duration.ofSeconds(1)).map(v -> "C"))
);
final Flux<Result<String, String>> results = queries.flatMap(query -> query.runCatching());
final Map<String, String> myMap = results.collectMap(Result::getId, Result::getOrNull)
.block();
for (Map.Entry<String, String> entry : myMap.entrySet()) {
System.out.printf("%s -> %s%n", entry.getKey(), entry.getValue());
}
}
}
Note : In the above example, we silently ignore any occurred error. However, when using the flux, you can test if a result is an error, and if it is, you are free to design your own error management (log, fail-first, send in another flux, etc.).
This outputs:
a -> A
b -> null
c -> C
I'm new to Hyperledger Composer. I'm following composer tutorial of how to interact with other business network
hyperledger_composer_tutorial
I have followed the step 1,2,3 mention in the tutorial. While i am trying to perform step 4: Create the assest
I am able to create participant in business network A.
I am getting error while creating asset in business network A
ValidationException: Unexpected properties for type org.hyperledger.composer.system.AddAsset: registryType, registryId
here is my code
Network A
/**
* My commodity trading network
*/
namespace org.example.mynetwork
asset Commodity identified by tradingSymbol {
o String tradingSymbol
o String description
o String mainExchange
o Double quantity
--> Trader owner
}
participant Trader identified by tradeId {
o String tradeId
o String firstName
o String lastName
}
transaction Trade {
--> Commodity commodity
--> Trader newOwner
}
2) logic.js
/**
* Track the trade of a commodity from one trader to another
* #param {org.example.mynetwork.Trade} trade - the trade to be processed
* #transaction
*/
async function tradeCommodity(trade) {
trade.commodity.owner = trade.newOwner;
const otherNetworkData = await getNativeAPI().invokeChaincode('other-tutorial-network', ['getResourceInRegistry', 'Asset', 'org.example.mynetwork.Commodity', trade.commodity.tradingSymbol], 'composerchannel');
const stringAsset = new Buffer(otherNetworkData.payload.toArrayBuffer()).toString('utf8');
const asset = getSerializer().fromJSON(JSON.parse(stringAsset));
trade.commodity.quantity = asset.quantity;
const assetRegistry = await getAssetRegistry('org.example.mynetwork.Commodity');
await assetRegistry.update(trade.commodity);
}
Network B
/**
* My commodity trading network
*/
namespace org.example.mynetwork
asset Commodity identified by tradingSymbol {
o String tradingSymbol
o String description
o String mainExchange
o Double quantity
--> Trader owner
}
participant Trader identified by tradeId {
o String tradeId
o String firstName
o String lastName
}
transaction Trade {
--> Commodity commodity
--> Trader newOwner
}
2) logic.js
/**
* Track the trade of a commodity from one trader to another
* #param {org.example.mynetwork.Trade} trade - the trade to be processed
* #transaction
*/
async function tradeCommodity(trade) {
trade.commodity.owner = trade.newOwner;
let assetRegistry = await getAssetRegistry('org.example.mynetwork.Commodity');
await assetRegistry.update(trade.commodity);
}
How do i resolve this problem??
I believe that the JSON that you are providing as an input in the command line could be wrong, Since you are adding an Asset of type Commodity.
Try this command instead
composer transaction submit --card networkA -d '{"$class": "org.example.mynetwork.Commodity","tradingSymbol": "Ag","owner": "resource: org.example.mynetwork.Trader#bob#example.com","description": "Some", "mainExchange": "exhange","quantity": 25}'
I keep getting this error everytime I try to compile my assignment
(unresolved_dot_expr type='#lvalue [Book]' location=/Users/BandManFabo/Desktop/Lab03/Lab03/Bookstore.swift:18:9 range=[/Users/BandManFabo/Desktop/Lab03/Lab03/Bookstore.swift:18:9 - line:18:9] field 'books' function_ref=unapplied
I am using a class called Book which is somewhat of a model for books in a Bookstore which is another class. Book.swift is below
import Foundation
class Book {
private var title:String
private var numOfPages:Int
private var price: Double
private var quantity: Int
init(title:String,pages:Int,price:Double,quantity:Int) {
self.title = title
self.numOfPages = pages
self.price = price
self.quantity = quantity
}
public func getTitle() -> String {
return self.title
}
public func getPrice() -> Double {
return self.price
}
public func getQuantity() -> Int {
return self.quantity
}
public func toString() -> String {
return "Title: \(self.title)\nNumber Of Pages: \(self.numOfPages)\nPrice: \(self.price)\nQuantity: \(self.quantity)"
}
public func subtractQuantity(amount: Int){
self.quantity = getQuantity() - amount
}
public func addQuantity(amount: Int){
self.quantity = getQuantity() + amount
}
}
Bookstore uses this class to run
import Foundation
class Bookstore {
private var totalbooks:Int
private var gross: Double
private static let MAXNUMOFBOOKS:Int = 1000
private var books: [Book]
//empty constructor for the bookstore
init() {
books = [Book](repeatElement(Book, count: Bookstore.MAXNUMOFBOOKS))
totalbooks = 0
gross = 0.0
}
/* Adds a new book to this bookstore.
* #param b the book to add
*/
public func addBook(b:Book){
if Bookstore.MAXNUMOFBOOKS < books.count{
books.append(b)
totalbooks = totalbooks+1
}else{
print("\nBookStore: I cannot add a new book into stock.")
}
}
/**
* Adds a certain quantity of a book already in stock.
*
* #param title the title of the the book
* #param quantity amount of copies to add
*/
public func addBookQuantity(title:String , quantity:Int){
// Search for the book...if found adjust the quantity,
// otherwise, inform the user that the book is not available
for currentBook in books {
if currentBook.getTitle() == title{
currentBook.addQuantity(amount: quantity)
return
}//end of if
}//end of for
// Book is not found in the bookstore
print("\nBookStore: I cannot increment the quantity of the book titled");
print("'\(title)' because it is not available in the bookstore.");
}// addBookQuantity
/**
* Checks if at least a certain number of copies of a particular book are in
* stock. Note: You can use this method to check if a book is already in the
* bookstore. This way, you won't create duplicate records of the same book.
*
* #param title the title of the book to search for
* #param quantity the desired number of copies
* #return
* #returns true if title exists with specified quantity; otherwise false
*/
public func inStock(title:String, quantity:Int) -> Bool {
// Search for the book...if found, adjust the quantity.
// otherwise, Book not in the BookStore.
for currentBook in books {
if currentBook.getTitle() == title{
if quantity <= currentBook.getQuantity(){
return true
}else{
return false
}
}//end of if
}//end of for
//Book not present
return false
}
/**
* Sells a particular number of copies of a certain book. If successful
* (i.e. enough books are in stock to sell), the quantity of the book is
* adjusted. Otherwise, no books are sold.
*
* #param title the title of the book to sell
* #param quantity the amount of books to sell
* #return
* #returns true if successful; otherwise false
*/
public func sellBook(title:String, quantity:Int) -> Bool {
var sellCheck: Bool = false
//will check to see if the books are instock
let retval:Bool = inStock(title: title, quantity: quantity)
//will do some operation if it is instock
if retval {
for currentBook in books {
if !sellCheck{
if currentBook.getTitle() == title{
currentBook.subtractQuantity(amount: quantity)
gross = gross + currentBook.getPrice() * Double(quantity)
sellCheck = true
}//end of most inner if
}//end of inner if
}//end of outer for
}//end of outer if
return retval
}
/**
* Lists information about each book in the bookstore
*/
public func listBooks(){
print("\nAll Books In Store and Info\n===============")
for currentBook in books {
print(currentBook.toString())
}
}
/**
* Lists the titles of all the books in the bookstore
*/
public func listTitles(){
// List all books titles
print("\nTitles of Books\n===============")
for currentBook in books {
print(currentBook.getTitle())
}
}
/**
* Returns the gross income of this bookstore.
*
* #return
* #returns gross income
*/
public func getIncome() -> Double {
return gross
}
}
Not entirely sure where the segmentation fault is coming from. I appreciate any help
Modify your init method in BookStore class
init() {
books = [Book]() //empty list
totalbooks = 0
gross = 0.0
}
I am new to AEM, consider my js would return itemList (for ex: var itemList = list.getItems();).
The skeleton of each Item would be:
interface Item {
/**
* Get the item's title.
*
* #return the title
*/
#Nonnull
String getTitle();
/**
* Get the item's localized title.
*
* #param locale the locale for localization
*
* #return the title
*/
#Nonnull
String getTitle(Locale locale);
/**
* Get the item's value.
*
* #return the value
*/
#Nonnull
String getValue();
}
How can I get the locale based title (i.e calling getTitle(locale)) in place of ${list.title} mentioned in the below HTML code of select tag (I need both title(locale) and value in the itemlist):
option value="${list.value}">${list.title}
From Sightly, you cannot access methods with parameters.
However, in the Use-API, the same global variables are available as in the Sightly execution context, and you can also pass parameters to the initialization of the Use-API.
In Java code, you can for instance access the page language with something like that:
PageManager pageManager = request.getResourceResolver().adaptTo(PageManager.class);
Page currentPage = pageManager.getContainingPage(request.getResource());
Locale locale = currentPage.getLanguage(false);
Else, to pass parameters to the Java Use-API, this is how it goes:
<div data-sly-use.foo="${'Foo' # locale='es'}">
<h1>${foo.titleLocalized}</h1>
</div>
And the corresponding Java:
public class Foo extends WCMUsePojo {
private String locale;
#Override
public void activate() throws Exception {
String locale = get("locale", String.class);
}
public String titleLocalized() {
...
}
}