Solved double spending, added haggling
This commit is contained in:
parent
c0fc73218e
commit
8f8bc9f4aa
@ -16,10 +16,14 @@
|
|||||||
<money>10</money>
|
<money>10</money>
|
||||||
<channels>MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE</channels>
|
<channels>MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE</channels>
|
||||||
</node>
|
</node>
|
||||||
<node type = "Distributor">
|
<node type = "Seller">
|
||||||
<money>1500</money>
|
<money>1500</money>
|
||||||
<channels>MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE</channels>
|
<channels>MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE</channels>
|
||||||
</node>
|
</node>
|
||||||
|
<node type = "Distributor">
|
||||||
|
<money>1000</money>
|
||||||
|
<channels>MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE</channels>
|
||||||
|
</node>
|
||||||
<node type = "Customer">
|
<node type = "Customer">
|
||||||
<money>250</money>
|
<money>250</money>
|
||||||
<channels>MEAT SALE;VEGETABLE SALE;FRUIT SALE</channels>
|
<channels>MEAT SALE;VEGETABLE SALE;FRUIT SALE</channels>
|
||||||
|
|||||||
@ -10,15 +10,16 @@
|
|||||||
generate
|
generate
|
||||||
consume
|
consume
|
||||||
doaction <product-operation-type>
|
doaction <product-operation-type>
|
||||||
doaction <product-operation-type> <product-name>
|
sell <product-type> <product-name>
|
||||||
sendreq <transaction-type> <product-type> <product-name>
|
buy <product-type> <produt-name> <product-price>
|
||||||
pass
|
pass
|
||||||
-->
|
-->
|
||||||
<scenarios>
|
<scenarios>
|
||||||
<scenario type="Farmer">
|
<scenario type="Farmer">
|
||||||
<steps>
|
<steps>
|
||||||
generate
|
generate
|
||||||
sendreq SALE FRUIT jablko
|
pass
|
||||||
|
sell FRUIT jablko
|
||||||
</steps>
|
</steps>
|
||||||
</scenario>
|
</scenario>
|
||||||
</scenarios>
|
</scenarios>
|
||||||
@ -1,6 +1,7 @@
|
|||||||
package cz.cvut.fel.sit.omo.foodchain.channel;
|
package cz.cvut.fel.sit.omo.foodchain.channel;
|
||||||
|
|
||||||
import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase;
|
import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase;
|
||||||
|
import cz.cvut.fel.sit.omo.foodchain.operation.ProductTransaction;
|
||||||
import cz.cvut.fel.sit.omo.foodchain.operation.Transaction;
|
import cz.cvut.fel.sit.omo.foodchain.operation.Transaction;
|
||||||
import cz.cvut.fel.sit.omo.foodchain.product.ProductType;
|
import cz.cvut.fel.sit.omo.foodchain.product.ProductType;
|
||||||
import cz.cvut.fel.sit.omo.foodchain.requirement.Requirement;
|
import cz.cvut.fel.sit.omo.foodchain.requirement.Requirement;
|
||||||
@ -81,6 +82,10 @@ public abstract class ChannelBase implements Observable {
|
|||||||
public void addTransaction(Transaction transaction)
|
public void addTransaction(Transaction transaction)
|
||||||
{
|
{
|
||||||
this.transactions.add(transaction);
|
this.transactions.add(transaction);
|
||||||
|
try {
|
||||||
|
((ProductTransaction) transaction).getProduct().setStateToInTransit();
|
||||||
|
}
|
||||||
|
catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disposeOf(Requirement requirement) { this.requirements.remove(requirement); }
|
public void disposeOf(Requirement requirement) { this.requirements.remove(requirement); }
|
||||||
|
|||||||
@ -61,10 +61,10 @@ public class ScenarioFactory
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "sell":
|
case "sell":
|
||||||
scenarioStep = new SendRequirementStep(node, TransactionType.SALE, ProductType.valueOf(parts[1]), parts[2], Double.parseDouble(parts[3]));
|
scenarioStep = new SendRequirementStep(node, TransactionType.SALE, ProductType.valueOf(parts[1]), parts[2]);
|
||||||
break;
|
break;
|
||||||
case "buy":
|
case "buy":
|
||||||
scenarioStep = new SendRequirementStep(node, TransactionType.PURCHASE, ProductType.valueOf(parts[1]), parts[2]);
|
scenarioStep = new SendRequirementStep(node, TransactionType.PURCHASE, ProductType.valueOf(parts[1]), parts[2], Double.parseDouble(parts[3]));
|
||||||
break;
|
break;
|
||||||
case "pass":
|
case "pass":
|
||||||
scenarioStep = new PassStep();
|
scenarioStep = new PassStep();
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType;
|
|||||||
import cz.cvut.fel.sit.omo.foodchain.operation.TransactionType;
|
import cz.cvut.fel.sit.omo.foodchain.operation.TransactionType;
|
||||||
import cz.cvut.fel.sit.omo.foodchain.product.Product;
|
import cz.cvut.fel.sit.omo.foodchain.product.Product;
|
||||||
|
|
||||||
|
import javax.naming.InsufficientResourcesException;
|
||||||
|
|
||||||
public class Farmer extends SellerNodeBase {
|
public class Farmer extends SellerNodeBase {
|
||||||
|
|
||||||
public Farmer(double startMoney) {
|
public Farmer(double startMoney) {
|
||||||
@ -15,6 +17,10 @@ public class Farmer extends SellerNodeBase {
|
|||||||
|
|
||||||
public void generateProduct(Product product) {
|
public void generateProduct(Product product) {
|
||||||
storeProduct(product);
|
storeProduct(product);
|
||||||
createRequirement(TransactionType.SALE, product.getProductType(), product.getName(), product.getPrice());
|
try {
|
||||||
|
createRequirement(TransactionType.SALE, product.getProductType(), product.getName(), product.getPrice());
|
||||||
|
} catch (InsufficientResourcesException e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,6 +84,7 @@ public class NodeBase implements ChannelObserver {
|
|||||||
|
|
||||||
public void receiveTransaction(ProductTransaction transaction) {
|
public void receiveTransaction(ProductTransaction transaction) {
|
||||||
if (validateSignature(transaction)) {
|
if (validateSignature(transaction)) {
|
||||||
|
transaction.getProduct().setStateToReadyForReception();
|
||||||
transaction.endTransaction();
|
transaction.endTransaction();
|
||||||
sendTransaction(transaction.getProduct().getPrice(), transaction.getNodeCreator(), transaction);
|
sendTransaction(transaction.getProduct().getPrice(), transaction.getNodeCreator(), transaction);
|
||||||
|
|
||||||
@ -114,20 +115,32 @@ public class NodeBase implements ChannelObserver {
|
|||||||
.findAny().ifPresent(channel -> channel.addRequirement(req));
|
.findAny().ifPresent(channel -> channel.addRequirement(req));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void createRequirement(TransactionType tType, ProductType pType, String pName, MonetaryAmount price) {
|
public void createRequirement(TransactionType tType, ProductType pType, String pName, MonetaryAmount price) throws InsufficientResourcesException {
|
||||||
|
if (price == null) {
|
||||||
|
try {
|
||||||
|
price = getProductFromStorage(pName, pType).getPrice();
|
||||||
|
}
|
||||||
|
catch (NullPointerException e) {
|
||||||
|
throw new InsufficientResourcesException("product unavailable");
|
||||||
|
}
|
||||||
|
}
|
||||||
Requirement req = new Requirement(this, tType, pType, pName, price);
|
Requirement req = new Requirement(this, tType, pType, pName, price);
|
||||||
subscribedChannels.keySet().stream()
|
subscribedChannels.keySet().stream()
|
||||||
.filter(ch -> ch.getProductType().equals(pType))
|
.filter(ch -> ch.getProductType().equals(pType))
|
||||||
.findAny().ifPresent(channel -> channel.addRequirement(req));
|
.findAny().ifPresent(channel -> channel.addRequirement(req));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void acceptRequirement(Requirement req) {
|
public void acceptRequirement(Requirement req) throws InsufficientResourcesException {
|
||||||
System.out.println(this.getClass().getSimpleName() + " accepted " + req.toString());
|
System.out.println(this.getClass().getSimpleName() + " accepted " + req.toString());
|
||||||
if (req.getTransactionType() == TransactionType.SALE) {
|
if (req.getTransactionType() == TransactionType.SALE) {
|
||||||
createRequirement(TransactionType.PURCHASE, req.getProductType(), req.getProductName(), req.getPrice());
|
createRequirement(TransactionType.PURCHASE, req.getProductType(), req.getProductName(), req.getPrice());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sendTransaction(getProductFromStorage(req.getProductName(), req.getProductType()), req.getCreator());
|
if (req.getPrice().isGreaterThanOrEqualTo(getProductFromStorage(req.getProductName(), req.getProductType()).getPrice().multiply(0.9))) {
|
||||||
|
getProductFromStorage(req.getProductName(), req.getProductType()).setPrice(req.getPrice());
|
||||||
|
sendTransaction(getProductFromStorage(req.getProductName(), req.getProductType()), req.getCreator());
|
||||||
|
}
|
||||||
|
else createRequirement(TransactionType.SALE, req.getProductType(), req.getProductName(), req.getPrice());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +157,7 @@ public class NodeBase implements ChannelObserver {
|
|||||||
|
|
||||||
|
|
||||||
public void doAction(ProductOperationType action, Product product) {
|
public void doAction(ProductOperationType action, Product product) {
|
||||||
Action actionProcess = new Action(this, product, action);
|
new Action(this, product, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -217,13 +230,17 @@ public class NodeBase implements ChannelObserver {
|
|||||||
@Override
|
@Override
|
||||||
public void update(Requirement requirement, ChannelBase channel) {
|
public void update(Requirement requirement, ChannelBase channel) {
|
||||||
if (senderPurchaserCheck(requirement) && transactionSubscriptionCheck(requirement, channel) && requirementCheck(requirement)) {
|
if (senderPurchaserCheck(requirement) && transactionSubscriptionCheck(requirement, channel) && requirementCheck(requirement)) {
|
||||||
channel.disposeOf(requirement);
|
try {
|
||||||
acceptRequirement(requirement);
|
acceptRequirement(requirement);
|
||||||
|
channel.disposeOf(requirement);
|
||||||
|
} catch (InsufficientResourcesException e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick() {
|
public void tick() {
|
||||||
receiveTransactions();
|
receiveTransactions();
|
||||||
System.out.println(this.getClass().getSimpleName() + ": " + money.getNumber());
|
//System.out.println(this.getClass().getSimpleName() + ": " + money.getNumber());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,8 @@ public class Action extends OperationBase {
|
|||||||
lastOperation = product.getCurrentOperation();
|
lastOperation = product.getCurrentOperation();
|
||||||
duration = type.getDuration();
|
duration = type.getDuration();
|
||||||
product.setCurrentOperation(this);
|
product.setCurrentOperation(this);
|
||||||
product.setStateToReadyForDispatch();
|
product.setStateToInAction();
|
||||||
|
System.out.println(toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void endAction() {
|
private void endAction() {
|
||||||
@ -45,4 +46,13 @@ public class Action extends OperationBase {
|
|||||||
public ProductOperationType getType() {
|
public ProductOperationType getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Action{" +
|
||||||
|
", product=" + product +
|
||||||
|
", type=" + type +
|
||||||
|
", duration=" + duration +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,17 @@
|
|||||||
package cz.cvut.fel.sit.omo.foodchain.operation;
|
package cz.cvut.fel.sit.omo.foodchain.operation;
|
||||||
|
|
||||||
|
import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType;
|
||||||
|
|
||||||
public enum ProductOperationType {
|
public enum ProductOperationType {
|
||||||
|
|
||||||
STORE_MEAT(10, -8);
|
STORE_MEAT(NodeType.All, 10, -8);
|
||||||
|
|
||||||
|
private final NodeType node;
|
||||||
private final int duration;
|
private final int duration;
|
||||||
private final int temperature;
|
private final int temperature;
|
||||||
|
|
||||||
ProductOperationType(int duration, int temperature) {
|
ProductOperationType(NodeType node, int duration, int temperature) {
|
||||||
|
this.node = node;
|
||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
this.temperature = temperature;
|
this.temperature = temperature;
|
||||||
}
|
}
|
||||||
@ -19,4 +23,6 @@ public enum ProductOperationType {
|
|||||||
public int getTemperature() {
|
public int getTemperature() {
|
||||||
return temperature;
|
return temperature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NodeType getNode() { return node; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -111,6 +111,17 @@ public class Product
|
|||||||
throw new IllegalStateException("Cannot set state READY_FOR_RECEPTION. Product has not been in transit!");
|
throw new IllegalStateException("Cannot set state READY_FOR_RECEPTION. Product has not been in transit!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set current product state to IN_ACTION. Throws IllegalStateException if the product is not AVAILABLE.
|
||||||
|
*/
|
||||||
|
public void setStateToInAction()
|
||||||
|
{
|
||||||
|
if(this.productState.equals(ProductState.AVAILABLE))
|
||||||
|
this.productState = ProductState.IN_ACTION;
|
||||||
|
else
|
||||||
|
throw new IllegalStateException("Cannot set state IN_ACTION. Product is not AVAILABLE!");
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public void setProductState(ProductState productState)
|
public void setProductState(ProductState productState)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,5 +2,5 @@ package cz.cvut.fel.sit.omo.foodchain.product;
|
|||||||
|
|
||||||
public enum ProductState
|
public enum ProductState
|
||||||
{
|
{
|
||||||
AVAILABLE, READY_FOR_DISPATCH, IN_TRANSIT, READY_FOR_RECEPTION;
|
AVAILABLE, READY_FOR_DISPATCH, IN_TRANSIT, READY_FOR_RECEPTION, IN_ACTION
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,8 @@ public class Requirement {
|
|||||||
private final String productName;
|
private final String productName;
|
||||||
private final MonetaryAmount price;
|
private final MonetaryAmount price;
|
||||||
private int TTL;
|
private int TTL;
|
||||||
|
private static int counter;
|
||||||
|
private int id;
|
||||||
|
|
||||||
public Requirement(NodeBase creator, TransactionType transactionType, ProductType productType, String productName, double price) {
|
public Requirement(NodeBase creator, TransactionType transactionType, ProductType productType, String productName, double price) {
|
||||||
this.creator = creator;
|
this.creator = creator;
|
||||||
@ -24,7 +26,8 @@ public class Requirement {
|
|||||||
this.productType = productType;
|
this.productType = productType;
|
||||||
this.productName = productName;
|
this.productName = productName;
|
||||||
this.price = Money.of(price, "USD");
|
this.price = Money.of(price, "USD");
|
||||||
TTL = 3;
|
this.TTL = 3;
|
||||||
|
this.id = counter++;
|
||||||
System.out.println(toString());
|
System.out.println(toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +37,8 @@ public class Requirement {
|
|||||||
this.productType = productType;
|
this.productType = productType;
|
||||||
this.productName = productName;
|
this.productName = productName;
|
||||||
this.price = price;
|
this.price = price;
|
||||||
TTL = 3;
|
this.TTL = 3;
|
||||||
|
this.id = counter++;
|
||||||
System.out.println(toString());
|
System.out.println(toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +71,8 @@ public class Requirement {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Requirement{" +
|
return "Requirement{" +
|
||||||
"creator=" + creator.getClass().getSimpleName() +
|
"id=" + id +
|
||||||
|
", creator=" + creator.getClass().getSimpleName() +
|
||||||
", transactionType=" + transactionType +
|
", transactionType=" + transactionType +
|
||||||
", productName='" + productName + '\'' +
|
", productName='" + productName + '\'' +
|
||||||
", TTL=" + TTL +
|
", TTL=" + TTL +
|
||||||
|
|||||||
@ -6,22 +6,25 @@ import cz.cvut.fel.sit.omo.foodchain.product.ProductType;
|
|||||||
import org.javamoney.moneta.Money;
|
import org.javamoney.moneta.Money;
|
||||||
|
|
||||||
import javax.money.MonetaryAmount;
|
import javax.money.MonetaryAmount;
|
||||||
|
import javax.naming.InsufficientResourcesException;
|
||||||
|
|
||||||
public class SendRequirementStep extends ScenarioStep {
|
public class SendRequirementStep extends ScenarioStep {
|
||||||
private final NodeBase node;
|
private final NodeBase node;
|
||||||
private final TransactionType tType;
|
private final TransactionType tType;
|
||||||
private final ProductType pType;
|
private final ProductType pType;
|
||||||
private final String pName;
|
private final String pName;
|
||||||
private final MonetaryAmount pPrice;
|
private MonetaryAmount pPrice;
|
||||||
|
|
||||||
|
// sell
|
||||||
public SendRequirementStep(NodeBase node, TransactionType tType, ProductType pType, String pName) {
|
public SendRequirementStep(NodeBase node, TransactionType tType, ProductType pType, String pName) {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.tType = tType;
|
this.tType = tType;
|
||||||
this.pType = pType;
|
this.pType = pType;
|
||||||
this.pName = pName;
|
this.pName = pName;
|
||||||
this.pPrice = Money.of(0, "USD");
|
this.pPrice = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// buy
|
||||||
public SendRequirementStep(NodeBase node, TransactionType tType, ProductType pType, String pName, Double price) {
|
public SendRequirementStep(NodeBase node, TransactionType tType, ProductType pType, String pName, Double price) {
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.tType = tType;
|
this.tType = tType;
|
||||||
@ -32,6 +35,10 @@ public class SendRequirementStep extends ScenarioStep {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
void execute() {
|
void execute() {
|
||||||
node.createRequirement(tType, pType, pName, pPrice);
|
try {
|
||||||
|
node.createRequirement(tType, pType, pName, pPrice);
|
||||||
|
} catch (InsufficientResourcesException e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,12 +13,12 @@ public class Ticker {
|
|||||||
private static Timer timer;
|
private static Timer timer;
|
||||||
|
|
||||||
public static void start() {
|
public static void start() {
|
||||||
timer = new Timer(500, actionEvent -> {
|
timer = new Timer(1000, actionEvent -> {
|
||||||
System.out.println("-----tick-----");
|
System.out.println("-----tick-----");
|
||||||
PoolDatabase db = FoodChain.getFactoryManager().getPoolDatabaseInstance();
|
PoolDatabase db = FoodChain.getFactoryManager().getPoolDatabaseInstance();
|
||||||
boolean productBool = db.getProductPoolInstance().findAll().stream().filter(Product::tick).count() == 0; // change duration of action
|
boolean productBool = db.getProductPoolInstance().findAll().stream().filter(Product::tick).count() == 0; // change duration of action
|
||||||
boolean scenarioBool = db.getScenarioPoolInstance().findAll().stream().filter(Scenario::tick).count() == 0; // do next step in scenario
|
|
||||||
boolean channelBool = db.getChannelPoolInstance().findAll().stream().filter(ChannelBase::tick).count() == 0; // change TTL of requirements
|
boolean channelBool = db.getChannelPoolInstance().findAll().stream().filter(ChannelBase::tick).count() == 0; // change TTL of requirements
|
||||||
|
boolean scenarioBool = db.getScenarioPoolInstance().findAll().stream().filter(Scenario::tick).count() == 0; // do next step in scenario
|
||||||
db.getNodePoolInstance().findAll().forEach(n -> n.tick()); // receive transactions
|
db.getNodePoolInstance().findAll().forEach(n -> n.tick()); // receive transactions
|
||||||
if (channelBool && productBool && scenarioBool) stop();
|
if (channelBool && productBool && scenarioBool) stop();
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user