diff --git a/conf/nodes.xml b/conf/nodes.xml index e327af1..5e55c72 100644 --- a/conf/nodes.xml +++ b/conf/nodes.xml @@ -16,10 +16,14 @@ 10 MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE - + 1500 MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE + + 1000 + MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE + 250 MEAT SALE;VEGETABLE SALE;FRUIT SALE diff --git a/conf/scenarios.xml b/conf/scenarios.xml index 68f28ef..d08dd00 100644 --- a/conf/scenarios.xml +++ b/conf/scenarios.xml @@ -10,15 +10,16 @@ generate consume doaction -doaction -sendreq +sell +buy pass --> generate - sendreq SALE FRUIT jablko + pass + sell FRUIT jablko \ No newline at end of file diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/channel/ChannelBase.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/channel/ChannelBase.java index 0f0b984..46d8095 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/channel/ChannelBase.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/channel/ChannelBase.java @@ -1,6 +1,7 @@ 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.operation.ProductTransaction; 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.requirement.Requirement; @@ -81,6 +82,10 @@ public abstract class ChannelBase implements Observable { public void addTransaction(Transaction transaction) { this.transactions.add(transaction); + try { + ((ProductTransaction) transaction).getProduct().setStateToInTransit(); + } + catch (Exception ignored) {} } public void disposeOf(Requirement requirement) { this.requirements.remove(requirement); } diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ScenarioFactory.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ScenarioFactory.java index d52163b..1fbd2a3 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ScenarioFactory.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ScenarioFactory.java @@ -61,10 +61,10 @@ public class ScenarioFactory } break; 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; 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; case "pass": scenarioStep = new PassStep(); diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Farmer.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Farmer.java index c65ffcf..23b9a6c 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Farmer.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Farmer.java @@ -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.product.Product; +import javax.naming.InsufficientResourcesException; + public class Farmer extends SellerNodeBase { public Farmer(double startMoney) { @@ -15,6 +17,10 @@ public class Farmer extends SellerNodeBase { public void generateProduct(Product 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()); + } } } diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/NodeBase.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/NodeBase.java index 7490577..018139d 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/NodeBase.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/NodeBase.java @@ -84,6 +84,7 @@ public class NodeBase implements ChannelObserver { public void receiveTransaction(ProductTransaction transaction) { if (validateSignature(transaction)) { + transaction.getProduct().setStateToReadyForReception(); transaction.endTransaction(); sendTransaction(transaction.getProduct().getPrice(), transaction.getNodeCreator(), transaction); @@ -114,20 +115,32 @@ public class NodeBase implements ChannelObserver { .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); subscribedChannels.keySet().stream() .filter(ch -> ch.getProductType().equals(pType)) .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()); if (req.getTransactionType() == TransactionType.SALE) { createRequirement(TransactionType.PURCHASE, req.getProductType(), req.getProductName(), req.getPrice()); } 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) { - Action actionProcess = new Action(this, product, action); + new Action(this, product, action); } @@ -217,13 +230,17 @@ public class NodeBase implements ChannelObserver { @Override public void update(Requirement requirement, ChannelBase channel) { if (senderPurchaserCheck(requirement) && transactionSubscriptionCheck(requirement, channel) && requirementCheck(requirement)) { - channel.disposeOf(requirement); - acceptRequirement(requirement); + try { + acceptRequirement(requirement); + channel.disposeOf(requirement); + } catch (InsufficientResourcesException e) { + System.err.println(e.getMessage()); + } } } public void tick() { receiveTransactions(); - System.out.println(this.getClass().getSimpleName() + ": " + money.getNumber()); + //System.out.println(this.getClass().getSimpleName() + ": " + money.getNumber()); } } diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/Action.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/Action.java index 8e35694..7733967 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/Action.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/Action.java @@ -17,7 +17,8 @@ public class Action extends OperationBase { lastOperation = product.getCurrentOperation(); duration = type.getDuration(); product.setCurrentOperation(this); - product.setStateToReadyForDispatch(); + product.setStateToInAction(); + System.out.println(toString()); } private void endAction() { @@ -45,4 +46,13 @@ public class Action extends OperationBase { public ProductOperationType getType() { return type; } + + @Override + public String toString() { + return "Action{" + + ", product=" + product + + ", type=" + type + + ", duration=" + duration + + '}'; + } } diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/ProductOperationType.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/ProductOperationType.java index 030ce8f..88868dc 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/ProductOperationType.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/ProductOperationType.java @@ -1,13 +1,17 @@ package cz.cvut.fel.sit.omo.foodchain.operation; +import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType; + public enum ProductOperationType { - STORE_MEAT(10, -8); + STORE_MEAT(NodeType.All, 10, -8); + private final NodeType node; private final int duration; private final int temperature; - ProductOperationType(int duration, int temperature) { + ProductOperationType(NodeType node, int duration, int temperature) { + this.node = node; this.duration = duration; this.temperature = temperature; } @@ -19,4 +23,6 @@ public enum ProductOperationType { public int getTemperature() { return temperature; } + + public NodeType getNode() { return node; } } diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/Product.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/Product.java index b60b3cc..6252afd 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/Product.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/Product.java @@ -111,6 +111,17 @@ public class Product 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) { diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/ProductState.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/ProductState.java index 2d7b4d1..906282e 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/ProductState.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/product/ProductState.java @@ -2,5 +2,5 @@ package cz.cvut.fel.sit.omo.foodchain.product; public enum ProductState { - AVAILABLE, READY_FOR_DISPATCH, IN_TRANSIT, READY_FOR_RECEPTION; + AVAILABLE, READY_FOR_DISPATCH, IN_TRANSIT, READY_FOR_RECEPTION, IN_ACTION } diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/requirement/Requirement.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/requirement/Requirement.java index 5e513cf..2caf0c6 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/requirement/Requirement.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/requirement/Requirement.java @@ -17,6 +17,8 @@ public class Requirement { private final String productName; private final MonetaryAmount price; private int TTL; + private static int counter; + private int id; public Requirement(NodeBase creator, TransactionType transactionType, ProductType productType, String productName, double price) { this.creator = creator; @@ -24,7 +26,8 @@ public class Requirement { this.productType = productType; this.productName = productName; this.price = Money.of(price, "USD"); - TTL = 3; + this.TTL = 3; + this.id = counter++; System.out.println(toString()); } @@ -34,7 +37,8 @@ public class Requirement { this.productType = productType; this.productName = productName; this.price = price; - TTL = 3; + this.TTL = 3; + this.id = counter++; System.out.println(toString()); } @@ -67,7 +71,8 @@ public class Requirement { @Override public String toString() { return "Requirement{" + - "creator=" + creator.getClass().getSimpleName() + + "id=" + id + + ", creator=" + creator.getClass().getSimpleName() + ", transactionType=" + transactionType + ", productName='" + productName + '\'' + ", TTL=" + TTL + diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/SendRequirementStep.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/SendRequirementStep.java index 862cc42..19e958f 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/SendRequirementStep.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/SendRequirementStep.java @@ -6,22 +6,25 @@ import cz.cvut.fel.sit.omo.foodchain.product.ProductType; import org.javamoney.moneta.Money; import javax.money.MonetaryAmount; +import javax.naming.InsufficientResourcesException; public class SendRequirementStep extends ScenarioStep { private final NodeBase node; private final TransactionType tType; private final ProductType pType; private final String pName; - private final MonetaryAmount pPrice; + private MonetaryAmount pPrice; + // sell public SendRequirementStep(NodeBase node, TransactionType tType, ProductType pType, String pName) { this.node = node; this.tType = tType; this.pType = pType; 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) { this.node = node; this.tType = tType; @@ -32,6 +35,10 @@ public class SendRequirementStep extends ScenarioStep { @Override void execute() { - node.createRequirement(tType, pType, pName, pPrice); + try { + node.createRequirement(tType, pType, pName, pPrice); + } catch (InsufficientResourcesException e) { + System.err.println(e.getMessage()); + } } } diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/util/Ticker.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/util/Ticker.java index 7ccf9b7..862c908 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/util/Ticker.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/util/Ticker.java @@ -13,12 +13,12 @@ public class Ticker { private static Timer timer; public static void start() { - timer = new Timer(500, actionEvent -> { + timer = new Timer(1000, actionEvent -> { System.out.println("-----tick-----"); PoolDatabase db = FoodChain.getFactoryManager().getPoolDatabaseInstance(); 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 scenarioBool = db.getScenarioPoolInstance().findAll().stream().filter(Scenario::tick).count() == 0; // do next step in scenario db.getNodePoolInstance().findAll().forEach(n -> n.tick()); // receive transactions if (channelBool && productBool && scenarioBool) stop(); });