From 80a52752e01708af93d241506783a098b0c7f1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Musil?= Date: Tue, 5 Jan 2021 18:43:47 +0100 Subject: [PATCH] Changed project structure, fixed some stuff --- README.MD | 4 +- conf/double-spending-scenario.xml | 27 +++++++++ conf/nodes.xml | 18 +++++- conf/scenarios.xml | 48 +++++++++++++++ {ŕesources => resources}/FoodChain.eap | Bin 1820672 -> 1820672 bytes .../cvut/fel/sit/omo/foodchain/FoodChain.java | 32 +++++----- .../omo/foodchain/channel/ChannelBase.java | 8 ++- .../omo/foodchain/channel/OtherChannel.java | 2 - .../omo/foodchain/factory/ChannelFactory.java | 1 - .../omo/foodchain/factory/NodeFactory.java | 16 ++--- .../omo/foodchain/factory/ProductFactory.java | 1 - .../foodchain/factory/ScenarioFactory.java | 6 +- .../fel/sit/omo/foodchain/node/Customer.java | 9 +-- .../sit/omo/foodchain/node/Distributor.java | 9 +-- .../fel/sit/omo/foodchain/node/Farmer.java | 8 +-- .../foodchain/node/{base => }/NodeBase.java | 57 +++++++++--------- .../foodchain/node/{enums => }/NodeType.java | 2 +- .../fel/sit/omo/foodchain/node/Processor.java | 9 +-- .../fel/sit/omo/foodchain/node/Seller.java | 9 +-- .../fel/sit/omo/foodchain/node/Storage.java | 25 +++++--- .../foodchain/node/base/BuyerNodeBase.java | 19 ------ .../foodchain/node/base/RetailerNodeBase.java | 29 --------- .../foodchain/node/base/SellerNodeBase.java | 23 ------- .../foodchain/node/helper/ProductCache.java | 23 +++++++ .../node/helper/RefusedRequirement.java | 29 +++++++++ .../foodchain/node/interfaces/IBuyerNode.java | 11 ---- .../node/interfaces/ISellerNode.java | 13 ---- .../sit/omo/foodchain/operation/Action.java | 8 +-- .../operation/FinancialTransaction.java | 2 +- .../foodchain/operation/OperationBase.java | 3 +- .../operation/ProductOperationType.java | 34 +++++------ .../operation/ProductTransaction.java | 4 +- .../omo/foodchain/operation/Transaction.java | 2 +- .../omo/foodchain/parser/ConsoleParser.java | 7 --- .../foodchain/parser/ParserResultElement.java | 1 - .../fel/sit/omo/foodchain/pool/NodePool.java | 2 +- .../sit/omo/foodchain/product/Product.java | 4 ++ .../reporting/FoodChainReportVisitor.java | 2 +- .../reporting/PartiesReportVisitor.java | 8 ++- .../reporting/ReportTextVisitor.java | 3 +- .../reporting/SecurityReportVisitor.java | 7 ++- .../foodchain/requirement/Requirement.java | 7 +-- .../omo/foodchain/scenario/DoActionStep.java | 15 ++--- .../omo/foodchain/scenario/ScenarioStep.java | 2 - .../scenario/SendRequirementStep.java | 2 +- .../sit/omo/foodchain/util/ReportLogger.java | 6 +- .../fel/sit/omo/foodchain/util/Ticker.java | 3 +- 47 files changed, 292 insertions(+), 268 deletions(-) create mode 100644 conf/double-spending-scenario.xml rename {ŕesources => resources}/FoodChain.eap (85%) rename src/main/java/cz/cvut/fel/sit/omo/foodchain/node/{base => }/NodeBase.java (89%) rename src/main/java/cz/cvut/fel/sit/omo/foodchain/node/{enums => }/NodeType.java (71%) delete mode 100644 src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/BuyerNodeBase.java delete mode 100644 src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/RetailerNodeBase.java delete mode 100644 src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/SellerNodeBase.java create mode 100644 src/main/java/cz/cvut/fel/sit/omo/foodchain/node/helper/ProductCache.java create mode 100644 src/main/java/cz/cvut/fel/sit/omo/foodchain/node/helper/RefusedRequirement.java delete mode 100644 src/main/java/cz/cvut/fel/sit/omo/foodchain/node/interfaces/IBuyerNode.java delete mode 100644 src/main/java/cz/cvut/fel/sit/omo/foodchain/node/interfaces/ISellerNode.java delete mode 100644 src/main/java/cz/cvut/fel/sit/omo/foodchain/parser/ConsoleParser.java diff --git a/README.MD b/README.MD index df0c28c..45a51f4 100644 --- a/README.MD +++ b/README.MD @@ -24,7 +24,7 @@ *** **Nefunkční požadavky:** - Aplikace nepožaduje autentizaci ani autorizaci. -- Do konzole se při každém ticku vypisují provedené úkony. Z toho pak vzniká PartiesReport. +- Do konzole se při každém ticku vypisují provedené úkony. Z toho pak vzniká TransactionReport. - V systému není centrální autorita, jednotlivé nody na sebe nevidí a jediná třída přes kterou procházejí všechny transakce je SignatureManager, který je v tomto směru naprosto neutrální. Aplikace běží pouze v jednom threadu. - Všechny proměnné jsou private nebo protected. Většina proměnných je final, abychom se vyhnuli např. změtným úpravám transakcí. - SignatureManager přidává na transakce Signature, které následně i validuje. Node zahazuje (ukládá jako neplatné) všechny nevalidní transakce. @@ -33,6 +33,6 @@ *** **Požadované výstupy:** - Diskrétní kroky jsou realizovány pomocí třídy Ticker resp. metody tick() na jednotlivých třídách. -- Diagramy jsou ve složce resources v souboru FoodChain.eap. BahavioralDiagram byl náš prvotní návrh a není aktuální. Ostatní reporty odpovídají realitě. +- Diagramy jsou ve složce resources v souboru FoodChain.eap. - Javadoc je ve složce resources v souboru FoodChain.html. *** \ No newline at end of file diff --git a/conf/double-spending-scenario.xml b/conf/double-spending-scenario.xml new file mode 100644 index 0000000..dbefab9 --- /dev/null +++ b/conf/double-spending-scenario.xml @@ -0,0 +1,27 @@ + + + + + + ]> + + + + + generate + pass + pass + sell FRUIT jablko + + + \ No newline at end of file diff --git a/conf/nodes.xml b/conf/nodes.xml index 5e55c72..3e471ff 100644 --- a/conf/nodes.xml +++ b/conf/nodes.xml @@ -1,31 +1,43 @@ - + + + ]> 100 + 1.2 + 1 MEAT PURCHASE;VEGETABLE PURCHASE;FRUIT PURCHASE - 10 + 200 + 1.3 + 0.9 MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE 1500 + 1.5 + 0.8 MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE 1000 + 1.2 + 1 MEAT SALE_AND_PURCHASE;VEGETABLE SALE_AND_PURCHASE;FRUIT SALE_AND_PURCHASE - 250 + 750 + 1 + 1 MEAT SALE;VEGETABLE SALE;FRUIT SALE \ No newline at end of file diff --git a/conf/scenarios.xml b/conf/scenarios.xml index 2c43e9d..3a413cf 100644 --- a/conf/scenarios.xml +++ b/conf/scenarios.xml @@ -19,7 +19,55 @@ pass generate + generate + generate + generate + generate + generate + generate + generate + generate + + + + + pass + pass + doaction DRY_FRUIT jablko + sell FRUIT hruška + sell FRUIT banán + sell VEGETABLE okurka + doaction STORE_VEGETABLE paprika sell FRUIT jablko + doaction STORE_VEGETABLE rajče + doaction BOIL_MEAT vepřové + sell VEGETABLE paprika + doaction GRILL_MEAT hovězí + sell VEGETABLE rajče + sell MEAT vepřové + sell MEAT kuřecí + sell MEAT hovězí + + + + + pass + pass + + + + + pass + pass + pass + + + + + pass + pass + pass + pass \ No newline at end of file diff --git a/ŕesources/FoodChain.eap b/resources/FoodChain.eap similarity index 85% rename from ŕesources/FoodChain.eap rename to resources/FoodChain.eap index c99f1eefc054343538e650c725ac543f1340786f..d31b161bd429a18ebb50336372e5f58099abc9a5 100644 GIT binary patch delta 44408 zcmeIb2Ygi3wm3YePfI4roJ=N@5E4ir2?@-kOfuATIte8ZT1WzfB0>NuqB21d5mAVg zh2<(u;94UfM+K3R!WD$z%B%GwmM8#{r8hkLNGup5E% z9pq_4c=jR^LXdY6X?wd6=j~M1f-dK63~LMOnTdZ=RM#gfMc`TwHi!T}#nO}g#+MD_ z;QMHcaaBOx0}y%AH~}6X!sf%jhOpt#eJC5QJU*2Dl!4i~>@nf6irpUu_Y7z6b$+5^ zN;;FAaazSJ=}3@I5sAEA2q5C&O57~ao*9;GfRvuq%@oz&f39i1p5>Jt++`A zVjtmW5Js{AwA|rUsvniG0z)YOdU++gtAN$76h^63sxQI!3L6skC8Ffl^v$@)s%IhR z3foarXFXLZy~2)F!^*9k2$O$doedb4kRr_bm30zCL1ZfrrN6K|o5HTLm1GFlu#h#w z2D{GgNmjnO###>P_VM4j6{^6?haCdz`pDzU%I!vyu^AO3ag2)VFCZAChNSnnzOec| zPImNTcoo-=C4eVDBtT7o20?#LK$j8$YEi|sQ%OjZ2v9?t!<^m1B0i8KKp;RQfY=XI z!~KW3VBbMnG-Rt0}KMLGpFO1yKxc}KOYIOiPj7 z5AUm`ZGfj$%m7|7`tp~*Vm}jL|5^hn>?2@GEx)3yJXR_Am7mPOyT9?8|JgvnAf)rn z>$7dFumt*YLM%MZ2}jwI&QQn;XY}rBizB5wI0T`R34<6>*yH5Lx6Wf#cZZPwx7C*x z{^^kqABjRQ@R9@#0Y5d*F^jcAB)p+TCQ&DZLnZ=ctxhM4Lh9>RJo81F3HY-410f1gx$ZbcfW}HG}SydUrFZv3fY`E!Y(=gK$mFaEg~% z_(fk2L2jUH%Tf*pJG}g9AvhA*k4$Y-2<*91r+OWa{}kP-_BI^~^1p z6hmL(oVYem(9>4hyWpEAg!sNoT;UHJbM*JFl9DHUpnNpZ3u!HN&z9gXD zu)kOsN7`Bfyf{fPl74Flq+IpRrZfd6ExdoF(=Y zIq{fqtnygpYGI@hAza`uRMb7M@%Qj4d`iV{91Jgz;$cjI)Qy4=4XaX-zbXy?v#(vd z2G}mG!oQ5TAIvR~!Yp^#eo*WB(a**B?|XOQq=|hqdRV(<SVkwlmVxxLuq0|m$7om+AmKPyO3)Mx)po8CtDFE!_k>TigWYELc z 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 RKdAKGl## System.out.println(ch.getProductType())); - // getFactoryManager().getPoolDatabaseInstance().getNodePoolInstance().findAll().stream().forEach(ch -> System.out.println(ch)); - // getFactoryManager().getPoolDatabaseInstance().getProductPoolInstance().findAll().stream().forEach(ch -> System.out.println(ch.getProductType() + " " + ch.getName())); - // getFactoryManager().getPoolDatabaseInstance().getScenarioPoolInstance().findAll().stream().forEach(ch -> ch.getSteps().stream().forEach(s -> System.out.println(s))); - Ticker.start(); - while (Ticker.getTimer().isRunning()) - { - ; - } + while (Ticker.getTimer().isRunning()) {} ReportingManager reportingManager = new ReportingManager(); System.out.println(reportingManager.generateReport()); } - public static FactoryManager getFactoryManager() - { - return factoryManager; - } + public static FactoryManager getFactoryManager() { return factoryManager; } /** * Provides connection between FoodChain and ConfigurationParser. 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 416c15d..7bee8ab 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,15 +1,17 @@ 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.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.reporting.ReportTextVisitor; import cz.cvut.fel.sit.omo.foodchain.requirement.Requirement; import cz.cvut.fel.sit.omo.foodchain.util.ChannelObserver; import cz.cvut.fel.sit.omo.foodchain.util.Observable; -import java.util.*; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; import java.util.stream.Collectors; /** diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/channel/OtherChannel.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/channel/OtherChannel.java index 0e6cbb8..949ce2d 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/channel/OtherChannel.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/channel/OtherChannel.java @@ -1,7 +1,5 @@ package cz.cvut.fel.sit.omo.foodchain.channel; -import cz.cvut.fel.sit.omo.foodchain.product.ProductType; - /** * Channel for transporting other products */ diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ChannelFactory.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ChannelFactory.java index 9e9ab2b..74e2561 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ChannelFactory.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ChannelFactory.java @@ -2,7 +2,6 @@ package cz.cvut.fel.sit.omo.foodchain.factory; import cz.cvut.fel.sit.omo.foodchain.channel.*; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; import cz.cvut.fel.sit.omo.foodchain.parser.ParserResultElement; import cz.cvut.fel.sit.omo.foodchain.product.ProductType; diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/NodeFactory.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/NodeFactory.java index e441d1b..759c5f9 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/NodeFactory.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/NodeFactory.java @@ -3,8 +3,6 @@ package cz.cvut.fel.sit.omo.foodchain.factory; import cz.cvut.fel.sit.omo.foodchain.FoodChain; import cz.cvut.fel.sit.omo.foodchain.channel.ChannelSubscriptionType; import cz.cvut.fel.sit.omo.foodchain.node.*; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; -import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType; import cz.cvut.fel.sit.omo.foodchain.parser.ParserResultElement; import cz.cvut.fel.sit.omo.foodchain.pool.ChannelPool; import cz.cvut.fel.sit.omo.foodchain.product.ProductType; @@ -30,6 +28,8 @@ public class NodeFactory NodeType nodeType = null; String subsChannels = ""; double startMoney = 0; + double margin = 0; + double acceptableDiscount = 0; try { @@ -37,6 +37,8 @@ public class NodeFactory subsChannels = input.getChild("channels"); startMoney = Double.parseDouble(input.getChild("money")); + margin = Double.parseDouble(input.getChild("margin")); + acceptableDiscount = Double.parseDouble(input.getChild("discount")); } catch (IllegalArgumentException e) { @@ -50,19 +52,19 @@ public class NodeFactory switch (Objects.requireNonNull(nodeType)) { case Farmer: - n = new Farmer(startMoney); + n = new Farmer(startMoney, margin, acceptableDiscount); break; case Processor: - n = new Processor(startMoney); + n = new Processor(startMoney, margin, acceptableDiscount); break; case Distributor: - n = new Distributor(startMoney); + n = new Distributor(startMoney, margin, acceptableDiscount); break; case Seller: - n = new Seller(startMoney); + n = new Seller(startMoney, margin, acceptableDiscount); break; case Customer: - n = new Customer(startMoney); + n = new Customer(startMoney, margin, acceptableDiscount); break; default: } diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ProductFactory.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ProductFactory.java index dbcc8d5..24e067d 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ProductFactory.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/factory/ProductFactory.java @@ -2,7 +2,6 @@ package cz.cvut.fel.sit.omo.foodchain.factory; import cz.cvut.fel.sit.omo.foodchain.parser.ParserResultElement; import cz.cvut.fel.sit.omo.foodchain.product.Product; -import cz.cvut.fel.sit.omo.foodchain.product.ProductState; import cz.cvut.fel.sit.omo.foodchain.product.ProductType; import java.util.logging.Level; 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 61daeed..01da370 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 @@ -3,7 +3,7 @@ package cz.cvut.fel.sit.omo.foodchain.factory; import cz.cvut.fel.sit.omo.foodchain.FoodChain; import cz.cvut.fel.sit.omo.foodchain.node.Customer; import cz.cvut.fel.sit.omo.foodchain.node.Farmer; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; import cz.cvut.fel.sit.omo.foodchain.operation.ProductOperationType; import cz.cvut.fel.sit.omo.foodchain.operation.TransactionType; import cz.cvut.fel.sit.omo.foodchain.parser.ParserResultElement; @@ -60,9 +60,7 @@ public class ScenarioFactory } else { - Product p = FoodChain.getFactoryManager().getPoolDatabaseInstance().getProductPoolInstance().findAll().stream() - .filter(pr -> pr.getName().equals(parts[2])).findFirst().orElse(null); - scenarioStep = new DoActionStep(node, ProductOperationType.valueOf(parts[1]), p); + scenarioStep = new DoActionStep(node, ProductOperationType.valueOf(parts[1]), parts[2]); } break; case "sell": diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Customer.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Customer.java index 371e181..adfbd44 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Customer.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Customer.java @@ -1,17 +1,14 @@ package cz.cvut.fel.sit.omo.foodchain.node; -import cz.cvut.fel.sit.omo.foodchain.node.base.BuyerNodeBase; -import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType; - import java.util.Random; /** * Customer node */ -public class Customer extends BuyerNodeBase { +public class Customer extends NodeBase { - public Customer(double startMoney) { - super(startMoney); + public Customer(double startMoney, double margin, double acceptableDiscount) { + super(startMoney, margin, acceptableDiscount); allowedSeller = NodeType.Distributor; allowedPurchaser = NodeType.None; nodeType = NodeType.Customer; diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Distributor.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Distributor.java index e188da8..53fec4c 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Distributor.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Distributor.java @@ -1,15 +1,12 @@ package cz.cvut.fel.sit.omo.foodchain.node; -import cz.cvut.fel.sit.omo.foodchain.node.base.RetailerNodeBase; -import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType; - /** * Distributor node */ -public class Distributor extends RetailerNodeBase { +public class Distributor extends NodeBase { - public Distributor(double startMoney) { - super(startMoney); + public Distributor(double startMoney, double margin, double acceptableDiscount) { + super(startMoney, margin, acceptableDiscount); allowedSeller = NodeType.Seller; allowedPurchaser = NodeType.Customer; this.nodeType = NodeType.Distributor; 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 6f4cb95..ef42674 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 @@ -1,7 +1,5 @@ package cz.cvut.fel.sit.omo.foodchain.node; -import cz.cvut.fel.sit.omo.foodchain.node.base.SellerNodeBase; -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; @@ -11,10 +9,10 @@ import java.util.logging.Level; /** * Farmer node */ -public class Farmer extends SellerNodeBase { +public class Farmer extends NodeBase { - public Farmer(double startMoney) { - super(startMoney); + public Farmer(double startMoney, double margin, double acceptableDiscount) { + super(startMoney, margin, acceptableDiscount); allowedSeller = NodeType.None; allowedPurchaser = NodeType.Processor; nodeType = NodeType.Farmer; 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/NodeBase.java similarity index 89% rename from src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/NodeBase.java rename to src/main/java/cz/cvut/fel/sit/omo/foodchain/node/NodeBase.java index 3af2903..da85b7e 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/NodeBase.java @@ -1,9 +1,8 @@ -package cz.cvut.fel.sit.omo.foodchain.node.base; +package cz.cvut.fel.sit.omo.foodchain.node; import cz.cvut.fel.sit.omo.foodchain.channel.ChannelBase; import cz.cvut.fel.sit.omo.foodchain.channel.ChannelSubscriptionType; -import cz.cvut.fel.sit.omo.foodchain.node.Storage; -import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType; +import cz.cvut.fel.sit.omo.foodchain.node.helper.RefusedRequirement; import cz.cvut.fel.sit.omo.foodchain.operation.*; import cz.cvut.fel.sit.omo.foodchain.product.Product; import cz.cvut.fel.sit.omo.foodchain.product.ProductState; @@ -16,7 +15,10 @@ import org.javamoney.moneta.Money; import javax.money.MonetaryAmount; import javax.naming.InsufficientResourcesException; -import java.util.*; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -32,6 +34,8 @@ public class NodeBase implements ChannelObserver { private final List refusedRequirements = new LinkedList<>(); private MonetaryAmount money; + private final double margin; + private final double acceptableDiscount; protected final Storage storage; protected NodeType nodeType; @@ -42,12 +46,16 @@ public class NodeBase implements ChannelObserver { this.nodeType = NodeType.None; this.storage = new Storage(this); this.money = Money.of(0, "USD"); + this.margin = 1.2; + this.acceptableDiscount = 0.9; } - public NodeBase(double m) { + public NodeBase(double m, double margin, double acceptableDiscount) { this.nodeType = NodeType.None; this.storage = new Storage(this); this.money = Money.of(m, "USD"); + this.margin = margin; + this.acceptableDiscount = acceptableDiscount; } @@ -111,10 +119,11 @@ public class NodeBase implements ChannelObserver { */ private void receiveTransaction(ProductTransaction transaction) { if (validateSignature(transaction)) { - transaction.getProduct().setStateToReadyForReception(); + Product p = transaction.getProduct(); + p.setStateToReadyForReception(); transaction.endTransaction(); - sendTransaction(transaction.getProduct().getPrice(), transaction.getNodeCreator(), transaction); - + sendTransaction(p.getPrice(), transaction.getNodeCreator(), transaction); + p.setPrice(p.getPrice().multiply(margin)); } else refuseTransaction(transaction); } @@ -164,7 +173,7 @@ public class NodeBase implements ChannelObserver { price = storage.getProduct(pName, pType).getPrice(); } catch (NullPointerException e) { refusedRequirements.add(new RefusedRequirement(tType, pType, pName, price)); - throw new InsufficientResourcesException("product unavailable"); + throw new InsufficientResourcesException(this.getClass().getSimpleName() + " tried to sell unavailable product " + pName); } } if (tType == TransactionType.SALE) { @@ -172,7 +181,7 @@ public class NodeBase implements ChannelObserver { storage.getProduct(pName, pType).setStateToInRequirement(); } catch (NullPointerException | IllegalStateException e) { refusedRequirements.add(new RefusedRequirement(tType, pType, pName, price)); - throw new InsufficientResourcesException("product unavailable"); + throw new InsufficientResourcesException(this.getClass().getSimpleName() + " tried to sell unavailable product " + pName); } } Requirement req = new Requirement(this, tType, pType, pName, price); @@ -192,7 +201,7 @@ public class NodeBase implements ChannelObserver { if (req.getTransactionType() == TransactionType.SALE) { createRequirement(TransactionType.PURCHASE, req.getProductType(), req.getProductName(), req.getPrice()); } else { - if (req.getPrice().isGreaterThanOrEqualTo(storage.getProduct(req.getProductName(), req.getProductType()).getPrice().multiply(0.9))) { + if (req.getPrice().isGreaterThanOrEqualTo(storage.getProduct(req.getProductName(), req.getProductType()).getPrice().multiply(acceptableDiscount))) { storage.getProduct(req.getProductName(), req.getProductType()).setPrice(req.getPrice()); sendTransaction(storage.getProduct(req.getProductName(), req.getProductType()), req.getCreator()); } else createRequirement(TransactionType.SALE, req.getProductType(), req.getProductName(), req.getPrice()); @@ -226,10 +235,10 @@ public class NodeBase implements ChannelObserver { * Proceed specific type of action on provided product if its possible. (Propagated to its storage). * * @param action type of product operation to do - * @param product product to proceed + * @param name product to proceed */ - public void doAction(ProductOperationType action, Product product) throws IllegalCallerException { - this.storage.doAction(action, product); + public void doAction(ProductOperationType action, String name) throws IllegalCallerException, InsufficientResourcesException { + this.storage.doAction(action, name); } /** @@ -270,6 +279,9 @@ public class NodeBase implements ChannelObserver { return allowedPurchaser; } + public double getMargin() { return margin; } + + public double getAcceptableDiscount() { return acceptableDiscount; } /** * Adds amount to current assets @@ -366,24 +378,11 @@ public class NodeBase implements ChannelObserver { } /** - * Receives transactions. + * Receives transactions and passes tick to storage. */ public void tick() { receiveTransactions(); - } - - private static class RefusedRequirement { - public final TransactionType tType; - public final ProductType pType; - public final String pName; - public final MonetaryAmount price; - - public RefusedRequirement(TransactionType tType, ProductType pType, String pName, MonetaryAmount price) { - this.tType = tType; - this.pType = pType; - this.pName = pName; - this.price = price; - } + storage.tick(); } public String accept(ReportTextVisitor visitor) { diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/enums/NodeType.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/NodeType.java similarity index 71% rename from src/main/java/cz/cvut/fel/sit/omo/foodchain/node/enums/NodeType.java rename to src/main/java/cz/cvut/fel/sit/omo/foodchain/node/NodeType.java index 4801d21..7003037 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/enums/NodeType.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/NodeType.java @@ -1,4 +1,4 @@ -package cz.cvut.fel.sit.omo.foodchain.node.enums; +package cz.cvut.fel.sit.omo.foodchain.node; /** * Enum class for all nodes diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Processor.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Processor.java index 4325eaf..2351148 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Processor.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Processor.java @@ -1,15 +1,12 @@ package cz.cvut.fel.sit.omo.foodchain.node; -import cz.cvut.fel.sit.omo.foodchain.node.base.RetailerNodeBase; -import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType; - /** * Processor node */ -public class Processor extends RetailerNodeBase { +public class Processor extends NodeBase { - public Processor(double startMoney) { - super(startMoney); + public Processor(double startMoney, double margin, double acceptableDiscount) { + super(startMoney, margin, acceptableDiscount); allowedSeller = NodeType.Farmer; allowedPurchaser = NodeType.Seller; this.nodeType = NodeType.Processor; diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Seller.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Seller.java index 3a82939..a7fd1a1 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Seller.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Seller.java @@ -1,15 +1,12 @@ package cz.cvut.fel.sit.omo.foodchain.node; -import cz.cvut.fel.sit.omo.foodchain.node.base.RetailerNodeBase; -import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType; - /** * Seller node */ -public class Seller extends RetailerNodeBase { +public class Seller extends NodeBase { - public Seller(double startMoney) { - super(startMoney); + public Seller(double startMoney, double margin, double acceptableDiscount) { + super(startMoney, margin, acceptableDiscount); allowedSeller = NodeType.Processor; allowedPurchaser = NodeType.Distributor; this.nodeType = NodeType.Seller; diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Storage.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Storage.java index 3ea84f9..bc443e7 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Storage.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/Storage.java @@ -1,13 +1,15 @@ package cz.cvut.fel.sit.omo.foodchain.node; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.node.helper.ProductCache; import cz.cvut.fel.sit.omo.foodchain.operation.Action; import cz.cvut.fel.sit.omo.foodchain.operation.ProductOperationType; import cz.cvut.fel.sit.omo.foodchain.product.Product; import cz.cvut.fel.sit.omo.foodchain.product.ProductType; +import javax.naming.InsufficientResourcesException; import java.util.LinkedList; import java.util.List; +import java.util.stream.Collectors; /** * Storage sub-node for storing products of other nodes @@ -16,6 +18,7 @@ public class Storage { private final NodeBase storageOwner; private final List products = new LinkedList<>(); + private final List cache = new LinkedList<>(); public Storage(NodeBase owner) { @@ -29,6 +32,7 @@ public class Storage public void storeProduct(Product product) { this.products.add(product); + this.cache.add(new ProductCache(product.getName(), product.getProductType())); } /** @@ -38,6 +42,7 @@ public class Storage public void storeProducts(List products) { this.products.addAll(products); + this.cache.addAll(products.stream().map(p -> new ProductCache(p.getName(), p.getProductType())).collect(Collectors.toList())); } /** @@ -56,6 +61,8 @@ public class Storage return products; } + public List getCache() { return cache; } + /** * Returns number of products in storage. * @return @@ -99,15 +106,16 @@ public class Storage /** * Proceed specific type of action on provided product if its possible. * @param action type of product operation to do - * @param product product to proceed + * @param productName product to process */ - public void doAction(ProductOperationType action, Product product) throws IllegalCallerException - { - if (action.getNode().equals(this.storageOwner.getNodeType())) - if (action.getProduct().equals(product.getProductType()) || action.getProduct().equals(ProductType.ALL)) + public void doAction(ProductOperationType action, String productName) throws IllegalCallerException, InsufficientResourcesException { + if (!containsProduct(productName, action.getProductType())) throw new InsufficientResourcesException(storageOwner.getClass().getSimpleName() + " tried to do action " + action.toString() + " to unavailable product " + productName); + Product product = getProduct(productName, action.getProductType()); + if (action.getNode().equals(this.storageOwner.getNodeType()) || action.getNode().equals(NodeType.All)) + if (action.getProductType().equals(product.getProductType()) || action.getProductType().equals(ProductType.ALL)) new Action(this.storageOwner, product, action); else - throw new IllegalCallerException("! IllegalCallerException in NodeBase. " + product.getProductType().toString() + " cannot be processed by action " + action.name() + " only for " + action.getProduct()); + throw new IllegalCallerException("! IllegalCallerException in NodeBase. " + product.getProductType().toString() + " cannot be processed by action " + action.name() + " only for " + action.getProductType()); else throw new IllegalCallerException("! IllegalCallerException in NodeBase. " + this.storageOwner.getNodeType().toString() + " cannot do action available only for " + action.getNode()); } @@ -122,4 +130,7 @@ public class Storage } + public void tick() { + cache.stream().filter(p -> containsProduct(p.getName(), p.getType())).forEach(ProductCache::addToDuration); + } } diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/BuyerNodeBase.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/BuyerNodeBase.java deleted file mode 100644 index c0ad0b9..0000000 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/BuyerNodeBase.java +++ /dev/null @@ -1,19 +0,0 @@ -package cz.cvut.fel.sit.omo.foodchain.node.base; - -import cz.cvut.fel.sit.omo.foodchain.node.interfaces.IBuyerNode; -import cz.cvut.fel.sit.omo.foodchain.product.Product; - -/** - * Base class for all buyer nodes - */ -public class BuyerNodeBase extends NodeBase implements IBuyerNode { - public BuyerNodeBase(double m){ - super(m); - } - - - @Override - public void buyProduct(Product product) { - - } -} diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/RetailerNodeBase.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/RetailerNodeBase.java deleted file mode 100644 index 77b6c9c..0000000 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/RetailerNodeBase.java +++ /dev/null @@ -1,29 +0,0 @@ -package cz.cvut.fel.sit.omo.foodchain.node.base; - -import cz.cvut.fel.sit.omo.foodchain.node.interfaces.IBuyerNode; -import cz.cvut.fel.sit.omo.foodchain.node.interfaces.ISellerNode; -import cz.cvut.fel.sit.omo.foodchain.product.Product; - -/** - * Base class for all retailer nodes - */ -public class RetailerNodeBase extends NodeBase implements IBuyerNode, ISellerNode { - public RetailerNodeBase(double startMoney) { - super(startMoney); - } - - @Override - public void sellProduct(Product product) { - - } - - @Override - public void addMargin(Product product) { - - } - - @Override - public void buyProduct(Product product) { - - } -} diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/SellerNodeBase.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/SellerNodeBase.java deleted file mode 100644 index 4008f55..0000000 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/SellerNodeBase.java +++ /dev/null @@ -1,23 +0,0 @@ -package cz.cvut.fel.sit.omo.foodchain.node.base; - -import cz.cvut.fel.sit.omo.foodchain.node.interfaces.ISellerNode; -import cz.cvut.fel.sit.omo.foodchain.product.Product; - -/** - * Base class for all seller nodes - */ -public class SellerNodeBase extends NodeBase implements ISellerNode { - public SellerNodeBase(double startMoney) { - super(startMoney); - } - - @Override - public void sellProduct(Product product) { - - } - - @Override - public void addMargin(Product product) { - - } -} diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/helper/ProductCache.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/helper/ProductCache.java new file mode 100644 index 0000000..14813d6 --- /dev/null +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/helper/ProductCache.java @@ -0,0 +1,23 @@ +package cz.cvut.fel.sit.omo.foodchain.node.helper; + +import cz.cvut.fel.sit.omo.foodchain.product.ProductType; + +public class ProductCache { + private final String name; + private final ProductType type; + private int duration; + + public ProductCache(String name, ProductType type) { + this.name = name; + this.type = type; + this.duration = 0; + } + + public String getName() { return name; } + + public ProductType getType() { return type; } + + public int getDuration() { return duration; } + + public void addToDuration() { duration++; } +} diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/helper/RefusedRequirement.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/helper/RefusedRequirement.java new file mode 100644 index 0000000..77beb64 --- /dev/null +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/helper/RefusedRequirement.java @@ -0,0 +1,29 @@ +package cz.cvut.fel.sit.omo.foodchain.node.helper; + +import cz.cvut.fel.sit.omo.foodchain.operation.TransactionType; +import cz.cvut.fel.sit.omo.foodchain.product.ProductType; + +import javax.money.MonetaryAmount; + +public class RefusedRequirement { + + private final TransactionType transactionType; + private final ProductType productType; + private final String productName; + private final MonetaryAmount price; + + public RefusedRequirement(TransactionType tType, ProductType pType, String pName, MonetaryAmount price) { + this.transactionType = tType; + this.productType = pType; + this.productName = pName; + this.price = price; + } + + public TransactionType getTransactionType() { return transactionType; } + + public ProductType getProductType() { return productType; } + + public String getProductName() { return productName; } + + public MonetaryAmount getPrice() { return price; } +} diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/interfaces/IBuyerNode.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/interfaces/IBuyerNode.java deleted file mode 100644 index 04e8848..0000000 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/interfaces/IBuyerNode.java +++ /dev/null @@ -1,11 +0,0 @@ -package cz.cvut.fel.sit.omo.foodchain.node.interfaces; - -import cz.cvut.fel.sit.omo.foodchain.product.Product; - -/** - * Interface for buyer nodes - */ -public interface IBuyerNode { - - void buyProduct(Product product); -} diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/interfaces/ISellerNode.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/interfaces/ISellerNode.java deleted file mode 100644 index 6da026f..0000000 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/node/interfaces/ISellerNode.java +++ /dev/null @@ -1,13 +0,0 @@ -package cz.cvut.fel.sit.omo.foodchain.node.interfaces; - -import cz.cvut.fel.sit.omo.foodchain.product.Product; - -/** - * Interface for seller nodes - */ -public interface ISellerNode { - - void sellProduct(Product product); - - void addMargin(Product product); -} 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 ae4e061..f98dc65 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 @@ -1,11 +1,10 @@ package cz.cvut.fel.sit.omo.foodchain.operation; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; import cz.cvut.fel.sit.omo.foodchain.product.Product; import cz.cvut.fel.sit.omo.foodchain.reporting.ReportTextVisitor; import java.util.logging.Level; -import java.util.logging.Logger; /** * Operation for processing products in storage @@ -39,11 +38,11 @@ public class Action extends OperationBase { * @return action is in progress */ public boolean tick() { + duration--; if (duration == 0) { endAction(); return false; } - else duration--; return true; } @@ -58,9 +57,10 @@ public class Action extends OperationBase { @Override public String toString() { return "Action{" + - ", product=" + product + + "product=" + product.getName() + ", type=" + type + ", duration=" + duration + + ", temperature=" + type.getTemperature() + '}'; } diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/FinancialTransaction.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/FinancialTransaction.java index 5b05015..9cd9afa 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/FinancialTransaction.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/FinancialTransaction.java @@ -1,6 +1,6 @@ package cz.cvut.fel.sit.omo.foodchain.operation; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; import cz.cvut.fel.sit.omo.foodchain.reporting.ReportTextVisitor; import javax.money.MonetaryAmount; diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/OperationBase.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/OperationBase.java index a7ca445..26e3be3 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/OperationBase.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/OperationBase.java @@ -1,7 +1,6 @@ package cz.cvut.fel.sit.omo.foodchain.operation; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; -import cz.cvut.fel.sit.omo.foodchain.reporting.PartiesReportVisitor; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; import cz.cvut.fel.sit.omo.foodchain.reporting.ReportTextVisitor; import java.time.LocalDateTime; 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 9a39cbe..324ca2b 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,6 +1,6 @@ package cz.cvut.fel.sit.omo.foodchain.operation; -import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType; +import cz.cvut.fel.sit.omo.foodchain.node.NodeType; import cz.cvut.fel.sit.omo.foodchain.product.ProductType; /** @@ -8,32 +8,32 @@ import cz.cvut.fel.sit.omo.foodchain.product.ProductType; */ public enum ProductOperationType { - STORE_MEAT(NodeType.All, ProductType.MEAT, 20, -8), - STORE_FRUIT(NodeType.All, ProductType.FRUIT, 8, 2), - STORE_VEGETABLE(NodeType.All, ProductType.VEGETABLE, 10, 2), - STORE_OTHER(NodeType.All, ProductType.OTHER, 30, 21), + STORE_MEAT(NodeType.All, ProductType.MEAT, 3, -8), + STORE_FRUIT(NodeType.All, ProductType.FRUIT, 3, 2), + STORE_VEGETABLE(NodeType.All, ProductType.VEGETABLE, 3, 2), + STORE_OTHER(NodeType.All, ProductType.OTHER, 3, 21), - WRAP_INTO_GIFT_PACKAGE(NodeType.Seller, ProductType.ALL, 1, -8), - UNWRAP(NodeType.All, ProductType.ALL, 1, 21), - CUT_TO_PIECES(NodeType.All, ProductType.ALL, 1, 21), + WRAP_INTO_GIFT_PACKAGE(NodeType.Seller, ProductType.ALL, 1, 21), + UNWRAP(NodeType.Customer, ProductType.ALL, 1, 21), + CUT_TO_PIECES(NodeType.Customer, ProductType.ALL, 1, 21), - BOIL_MEAT(NodeType.All, ProductType.MEAT, 1, 21), - GRILL_MEAT(NodeType.All, ProductType.MEAT, 1, 21), - SMOKE_MEAT(NodeType.All, ProductType.MEAT, 1, 21), - DRY_MEAT(NodeType.All, ProductType.MEAT, 1, 21), + BOIL_MEAT(NodeType.Processor, ProductType.MEAT, 2, 100), + GRILL_MEAT(NodeType.Processor, ProductType.MEAT, 2, 200), + SMOKE_MEAT(NodeType.Processor, ProductType.MEAT, 7, 60), + DRY_MEAT(NodeType.Processor, ProductType.MEAT, 5, 55), - DRY_FRUIT(NodeType.All, ProductType.FRUIT, 1, 21), - FREEZE_DRY_FRUIT(NodeType.All, ProductType.FRUIT, 1, 21); + DRY_FRUIT(NodeType.Processor, ProductType.FRUIT, 4, 45), + FREEZE_DRY_FRUIT(NodeType.Processor, ProductType.FRUIT, 3, -195); private final NodeType node; - private final ProductType product; + private final ProductType productType; private final int duration; private final int temperature; ProductOperationType(NodeType node, ProductType product, int duration, int temperature) { this.node = node; - this.product = product; + this.productType = product; this.duration = duration; this.temperature = temperature; } @@ -53,5 +53,5 @@ public enum ProductOperationType return node; } - public ProductType getProduct() { return product; } + public ProductType getProductType() { return productType; } } diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/ProductTransaction.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/ProductTransaction.java index 503e20a..91946ab 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/ProductTransaction.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/ProductTransaction.java @@ -1,6 +1,6 @@ package cz.cvut.fel.sit.omo.foodchain.operation; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; import cz.cvut.fel.sit.omo.foodchain.product.Product; import cz.cvut.fel.sit.omo.foodchain.product.ProductState; import cz.cvut.fel.sit.omo.foodchain.reporting.ReportTextVisitor; @@ -20,7 +20,7 @@ public class ProductTransaction extends Transaction { super(creator, receiver, transactionType, product.getCurrentOperation()); this.product = product; type = null; - if (product == null || product.getProductState() != ProductState.IN_REQUIREMENT) throw new InsufficientResourcesException("product unavailable"); + if (product == null || product.getProductState() != ProductState.IN_REQUIREMENT) throw new InsufficientResourcesException(creator.getClass().getSimpleName() + " tried to sell unavailable product " + product.getName() + " to " + receiver.getClass().getSimpleName()); product.setCurrentOperation(this); product.setStateToReadyForDispatch(); creator.getStorage().removeProduct(product); diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/Transaction.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/Transaction.java index 7985a63..991ac80 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/Transaction.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/Transaction.java @@ -1,6 +1,6 @@ package cz.cvut.fel.sit.omo.foodchain.operation; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; import cz.cvut.fel.sit.omo.foodchain.reporting.ReportTextVisitor; import cz.cvut.fel.sit.omo.foodchain.signature.Signature; import cz.cvut.fel.sit.omo.foodchain.signature.SignatureManager; diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/parser/ConsoleParser.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/parser/ConsoleParser.java deleted file mode 100644 index f3498ac..0000000 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/parser/ConsoleParser.java +++ /dev/null @@ -1,7 +0,0 @@ -package cz.cvut.fel.sit.omo.foodchain.parser; - -/** - * Parser for console input - */ -public class ConsoleParser { -} diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/parser/ParserResultElement.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/parser/ParserResultElement.java index b2307bf..c7fef55 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/parser/ParserResultElement.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/parser/ParserResultElement.java @@ -1,7 +1,6 @@ package cz.cvut.fel.sit.omo.foodchain.parser; import java.util.HashMap; -import java.util.LinkedList; import java.util.Map; /** diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/pool/NodePool.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/pool/NodePool.java index 04f976f..0a21662 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/pool/NodePool.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/pool/NodePool.java @@ -1,6 +1,6 @@ package cz.cvut.fel.sit.omo.foodchain.pool; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; /** *Pool for storing all nodes 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 ef24907..605df65 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 @@ -16,6 +16,7 @@ public class Product private ProductType productType; private OperationBase currentOperation; private MonetaryAmount price; + private final MonetaryAmount startPrice; private String name; @@ -25,6 +26,7 @@ public class Product this.productType = productType; this.productState = ProductState.AVAILABLE; this.price = Money.of(m, "USD"); + this.startPrice = Money.of(m, "USD"); } /** @@ -151,6 +153,8 @@ public class Product public void setPrice(MonetaryAmount price) { this.price = price; } + public MonetaryAmount getStartPrice() { return startPrice; } + public String accept(ReportTextVisitor visitor){ return visitor.visit(this); } diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/FoodChainReportVisitor.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/FoodChainReportVisitor.java index 656a165..528768c 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/FoodChainReportVisitor.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/FoodChainReportVisitor.java @@ -1,6 +1,6 @@ package cz.cvut.fel.sit.omo.foodchain.reporting; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; import cz.cvut.fel.sit.omo.foodchain.operation.Action; import cz.cvut.fel.sit.omo.foodchain.operation.FinancialTransaction; import cz.cvut.fel.sit.omo.foodchain.operation.ProductTransaction; diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/PartiesReportVisitor.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/PartiesReportVisitor.java index 6773028..93dafe6 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/PartiesReportVisitor.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/PartiesReportVisitor.java @@ -1,8 +1,10 @@ package cz.cvut.fel.sit.omo.foodchain.reporting; -import cz.cvut.fel.sit.omo.foodchain.channel.ChannelBase; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; -import cz.cvut.fel.sit.omo.foodchain.operation.*; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.operation.Action; +import cz.cvut.fel.sit.omo.foodchain.operation.FinancialTransaction; +import cz.cvut.fel.sit.omo.foodchain.operation.OperationBase; +import cz.cvut.fel.sit.omo.foodchain.operation.ProductTransaction; import cz.cvut.fel.sit.omo.foodchain.product.Product; import java.util.LinkedList; diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/ReportTextVisitor.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/ReportTextVisitor.java index 62d2531..c75daa5 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/ReportTextVisitor.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/ReportTextVisitor.java @@ -1,8 +1,7 @@ package cz.cvut.fel.sit.omo.foodchain.reporting; import cz.cvut.fel.sit.omo.foodchain.FoodChain; -import cz.cvut.fel.sit.omo.foodchain.channel.ChannelBase; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; import cz.cvut.fel.sit.omo.foodchain.operation.*; import cz.cvut.fel.sit.omo.foodchain.pool.PoolDatabase; import cz.cvut.fel.sit.omo.foodchain.product.Product; diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/SecurityReportVisitor.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/SecurityReportVisitor.java index f1bc0f8..6f01924 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/SecurityReportVisitor.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/reporting/SecurityReportVisitor.java @@ -1,8 +1,9 @@ package cz.cvut.fel.sit.omo.foodchain.reporting; -import cz.cvut.fel.sit.omo.foodchain.channel.ChannelBase; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; -import cz.cvut.fel.sit.omo.foodchain.operation.*; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.operation.Action; +import cz.cvut.fel.sit.omo.foodchain.operation.FinancialTransaction; +import cz.cvut.fel.sit.omo.foodchain.operation.ProductTransaction; import cz.cvut.fel.sit.omo.foodchain.product.Product; public class SecurityReportVisitor implements ReportTextVisitor { 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 12b8bac..b256a7b 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 @@ -1,14 +1,11 @@ package cz.cvut.fel.sit.omo.foodchain.requirement; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; import cz.cvut.fel.sit.omo.foodchain.operation.TransactionType; -import cz.cvut.fel.sit.omo.foodchain.product.ProductState; import cz.cvut.fel.sit.omo.foodchain.product.ProductType; import cz.cvut.fel.sit.omo.foodchain.util.Ticker; -import org.javamoney.moneta.Money; import javax.money.MonetaryAmount; -import javax.naming.InsufficientResourcesException; import java.util.logging.Level; import java.util.logging.Logger; @@ -33,7 +30,7 @@ public class Requirement { this.productType = productType; this.productName = productName; this.price = price; - this.TTL = 3; + this.TTL = 5; this.id = counter++; LOGGER.log(Level.INFO, toString()); diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/DoActionStep.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/DoActionStep.java index b30ed76..eceaf75 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/DoActionStep.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/DoActionStep.java @@ -1,9 +1,10 @@ package cz.cvut.fel.sit.omo.foodchain.scenario; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; import cz.cvut.fel.sit.omo.foodchain.operation.ProductOperationType; import cz.cvut.fel.sit.omo.foodchain.product.Product; +import javax.naming.InsufficientResourcesException; import java.util.logging.Level; /** @@ -12,12 +13,12 @@ import java.util.logging.Level; public class DoActionStep extends ScenarioStep { private final NodeBase nodeBase; private final ProductOperationType productOperationType; - private final Product product; + private final String productName; - public DoActionStep(NodeBase node, ProductOperationType productOperationType, Product product){ + public DoActionStep(NodeBase node, ProductOperationType productOperationType, String name){ this.nodeBase = node; this.productOperationType = productOperationType; - this.product = product; + this.productName = name; } public DoActionStep(NodeBase node, ProductOperationType productOperationType){ @@ -31,14 +32,14 @@ public class DoActionStep extends ScenarioStep { @Override void execute() { try { - if (product != null) { - nodeBase.doAction(productOperationType, product); + if (productName != null) { + nodeBase.doAction(productOperationType, productName); } else { nodeBase.doAction(productOperationType); } } - catch (IllegalCallerException e) { + catch (IllegalCallerException | InsufficientResourcesException e) { LOGGER.log(Level.SEVERE, e.getMessage()); } } diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/ScenarioStep.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/ScenarioStep.java index 4b59baf..1d3b603 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/ScenarioStep.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/scenario/ScenarioStep.java @@ -1,7 +1,5 @@ package cz.cvut.fel.sit.omo.foodchain.scenario; -import cz.cvut.fel.sit.omo.foodchain.operation.OperationBase; - import java.util.logging.Logger; /** 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 1ead730..fb8572e 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 @@ -1,6 +1,6 @@ package cz.cvut.fel.sit.omo.foodchain.scenario; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; +import cz.cvut.fel.sit.omo.foodchain.node.NodeBase; import cz.cvut.fel.sit.omo.foodchain.operation.TransactionType; import cz.cvut.fel.sit.omo.foodchain.product.ProductType; import org.javamoney.moneta.Money; diff --git a/src/main/java/cz/cvut/fel/sit/omo/foodchain/util/ReportLogger.java b/src/main/java/cz/cvut/fel/sit/omo/foodchain/util/ReportLogger.java index d5c31ff..a2e9b6d 100644 --- a/src/main/java/cz/cvut/fel/sit/omo/foodchain/util/ReportLogger.java +++ b/src/main/java/cz/cvut/fel/sit/omo/foodchain/util/ReportLogger.java @@ -16,11 +16,7 @@ public class ReportLogger extends Handler @Override public void publish(LogRecord record) { StringBuilder sb = new StringBuilder(); - sb.append(record.getSourceClassName()) - .append("#") - .append(record.getSourceMethodName()) - .append(" - ") - .append(record.getMessage()); + sb.append(record.getMessage()); if(record.getLevel().equals(Level.WARNING) || record.getLevel().equals(Level.SEVERE)) { 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 0647543..8114450 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 @@ -2,7 +2,6 @@ package cz.cvut.fel.sit.omo.foodchain.util; import cz.cvut.fel.sit.omo.foodchain.FoodChain; import cz.cvut.fel.sit.omo.foodchain.channel.ChannelBase; -import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase; import cz.cvut.fel.sit.omo.foodchain.pool.PoolDatabase; import cz.cvut.fel.sit.omo.foodchain.product.Product; import cz.cvut.fel.sit.omo.foodchain.scenario.Scenario; @@ -29,8 +28,8 @@ public class Ticker { PoolDatabase db = FoodChain.getFactoryManager().getPoolDatabaseInstance(); boolean productBool = db.getProductPoolInstance().findAll().stream().filter(Product::tick).count() == 0; // change duration of action 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 + boolean scenarioBool = db.getScenarioPoolInstance().findAll().stream().filter(Scenario::tick).count() == 0; // do next step in scenario if (channelBool && productBool && scenarioBool) stop(); }); timer.start();