Merge branch 'develop' into feature/text_report_impl

This commit is contained in:
Nikita Iryupin 2020-12-27 17:21:56 +01:00
commit 3118f91a42
18 changed files with 172 additions and 48 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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.reporting.ReportTextVisitor; import cz.cvut.fel.sit.omo.foodchain.reporting.ReportTextVisitor;
@ -82,6 +83,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); }

View File

@ -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();

View File

@ -11,6 +11,7 @@ public class Customer extends BuyerNodeBase {
super(startMoney); super(startMoney);
allowedSeller = NodeType.Distributor; allowedSeller = NodeType.Distributor;
allowedPurchaser = NodeType.None; allowedPurchaser = NodeType.None;
this.nodeType = NodeType.Customer;
} }
public void consumeProduct() { public void consumeProduct() {

View File

@ -9,5 +9,6 @@ public class Distributor extends RetailerNodeBase {
super(startMoney); super(startMoney);
allowedSeller = NodeType.Seller; allowedSeller = NodeType.Seller;
allowedPurchaser = NodeType.Customer; allowedPurchaser = NodeType.Customer;
this.nodeType = NodeType.Distributor;
} }
} }

View File

@ -5,16 +5,23 @@ 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) {
super(startMoney); super(startMoney);
allowedSeller = NodeType.None; allowedSeller = NodeType.None;
allowedPurchaser = NodeType.Processor; allowedPurchaser = NodeType.Processor;
this.nodeType = NodeType.Farmer;
} }
public void generateProduct(Product product) { public void generateProduct(Product product) {
storeProduct(product); storeProduct(product);
try {
createRequirement(TransactionType.SALE, product.getProductType(), product.getName(), product.getPrice()); createRequirement(TransactionType.SALE, product.getProductType(), product.getName(), product.getPrice());
} catch (InsufficientResourcesException e) {
System.err.println(e.getMessage());
}
} }
} }

View File

@ -9,5 +9,6 @@ public class Processor extends RetailerNodeBase {
super(startMoney); super(startMoney);
allowedSeller = NodeType.Farmer; allowedSeller = NodeType.Farmer;
allowedPurchaser = NodeType.Seller; allowedPurchaser = NodeType.Seller;
this.nodeType = NodeType.Processor;
} }
} }

View File

@ -9,5 +9,6 @@ public class Seller extends RetailerNodeBase {
super(startMoney); super(startMoney);
allowedSeller = NodeType.Processor; allowedSeller = NodeType.Processor;
allowedPurchaser = NodeType.Distributor; allowedPurchaser = NodeType.Distributor;
this.nodeType = NodeType.Seller;
} }
} }

View File

@ -27,21 +27,24 @@ public class NodeBase implements ChannelObserver {
private final List<Transaction> refusedTransactions; private final List<Transaction> refusedTransactions;
private MonetaryAmount money; private MonetaryAmount money;
protected NodeType nodeType;
protected NodeType allowedSeller; protected NodeType allowedSeller;
protected NodeType allowedPurchaser; protected NodeType allowedPurchaser;
public NodeBase() { public NodeBase() {
subscribedChannels = new HashMap<>(); this.nodeType = NodeType.None;
products = new LinkedList<>(); this.subscribedChannels = new HashMap<>();
refusedTransactions = new LinkedList<>(); this.products = new LinkedList<>();
money = Money.of(0, "USD"); this.refusedTransactions = new LinkedList<>();
this.money = Money.of(0, "USD");
} }
public NodeBase(double m) { public NodeBase(double m) {
subscribedChannels = new HashMap<>(); this.subscribedChannels = new HashMap<>();
products = new LinkedList<>(); this.products = new LinkedList<>();
refusedTransactions = new LinkedList<>(); this.refusedTransactions = new LinkedList<>();
money = Money.of(m, "USD"); this.money = Money.of(m, "USD");
} }
@ -84,6 +87,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,21 +118,33 @@ 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.nodeType.toString() + " 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 {
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()); sendTransaction(getProductFromStorage(req.getProductName(), req.getProductType()), req.getCreator());
} }
else createRequirement(TransactionType.SALE, req.getProductType(), req.getProductName(), req.getPrice());
}
} }
@ -143,13 +159,27 @@ public class NodeBase implements ChannelObserver {
} }
public void doAction(ProductOperationType action, Product product) { /**
Action actionProcess = new Action(this, product, action); * Proceed specific type of action on provided product if its possible.
* @param action type of product operation to do
* @param product product to proceed
*/
public void doAction(ProductOperationType action, Product product) throws IllegalCallerException
{
if(action.getNode().equals(this.nodeType))
new Action(this, product, action);
else
throw new IllegalCallerException("! IllegalCallerException in NodeBase. " + this.nodeType.toString() + " cannot do action available only for "+action.getNode());
} }
public void doAction(ProductOperationType action) { /**
//create new action * Calls specific ProductOperation on each product in stock
* @param action ProductOperationType
*/
public void doAction(ProductOperationType action)
{
this.products.forEach(t -> new Action(this, t, action));
} }
@ -208,11 +238,11 @@ public class NodeBase implements ChannelObserver {
} }
boolean senderPurchaserCheck(Requirement req) { boolean senderPurchaserCheck(Requirement req) {
String simpleName = req.getCreator().getClass().getSimpleName(); NodeType creatorType = req.getCreator().nodeType;
return !req.getCreator().equals(this) && return !req.getCreator().equals(this) &&
(((allowedSeller == NodeType.valueOf(simpleName) || allowedSeller == NodeType.All) && (req.getTransactionType() == TransactionType.SALE)) || (((allowedSeller == creatorType || allowedSeller == NodeType.All) && (req.getTransactionType() == TransactionType.SALE)) ||
((allowedPurchaser == NodeType.valueOf(simpleName) || allowedPurchaser == NodeType.All) && req.getTransactionType() == TransactionType.PURCHASE)); ((allowedPurchaser == creatorType || allowedPurchaser == NodeType.All) && req.getTransactionType() == TransactionType.PURCHASE));
} }
boolean transactionSubscriptionCheck(Requirement requirement, ChannelBase channel) { boolean transactionSubscriptionCheck(Requirement requirement, ChannelBase channel) {
@ -237,14 +267,18 @@ 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());
} }
public String accept(ReportTextVisitor visitor){ public String accept(ReportTextVisitor visitor){

View File

@ -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 +
'}';
}
} }

View File

@ -1,22 +1,52 @@
package cz.cvut.fel.sit.omo.foodchain.operation; package cz.cvut.fel.sit.omo.foodchain.operation;
public enum ProductOperationType { import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType;
STORE_MEAT(10, -8); public enum ProductOperationType
{
STORE_MEAT(NodeType.All, 20, -8),
STORE_FRUIT(NodeType.All, 8, 2),
STORE_VEGETABLE(NodeType.All, 10, 2),
STORE_OTHER(NodeType.All, 30, 21),
WRAP_INTO_GIFT_PACKAGE(NodeType.Seller, 1, -8),
UNWRAP(NodeType.All, 1, 21),
CUT_TO_PIECES(NodeType.All, 1, 21),
BOIL_MEAT(NodeType.All, 1, 21),
GRILL_MEAT(NodeType.All, 1, 21),
SMOKE_MEAT(NodeType.All, 1, 21),
DRY_MEAT(NodeType.All, 1, 21),
DRY_FRUIT(NodeType.All, 1, 21),
FREEZE_DRY_FRUIT(NodeType.All, 1, 21);
//todo add product type allowed for this action
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;
} }
public int getDuration() { public int getDuration()
{
return duration; return duration;
} }
public int getTemperature() { public int getTemperature()
{
return temperature; return temperature;
} }
public NodeType getNode()
{
return node;
}
} }

View File

@ -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)
{ {

View File

@ -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
} }

View File

@ -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 +

View File

@ -22,11 +22,17 @@ public class DoActionStep extends ScenarioStep {
@Override @Override
void execute() { void execute() {
if (product != null){ //todo maybe do a better error handling
try {
if (product != null) {
nodeBase.doAction(productOperationType, product); nodeBase.doAction(productOperationType, product);
} }
else { else {
nodeBase.doAction(productOperationType); nodeBase.doAction(productOperationType);
} }
} }
catch (IllegalCallerException e) {
System.err.println(e.getMessage());
}
}
} }

View File

@ -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() {
try {
node.createRequirement(tType, pType, pName, pPrice); node.createRequirement(tType, pType, pName, pPrice);
} catch (InsufficientResourcesException e) {
System.err.println(e.getMessage());
}
} }
} }

View File

@ -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();
}); });