Merge branch 'develop' into feature/text_report_impl

# Conflicts:
#	src/main/java/cz/cvut/fel/sit/omo/foodchain/node/base/NodeBase.java
#	src/main/java/cz/cvut/fel/sit/omo/foodchain/operation/OperationBase.java
This commit is contained in:
Nikita Iryupin 2021-01-04 13:22:06 +01:00
commit 099dd81246
60 changed files with 525 additions and 117 deletions

View File

@ -9,12 +9,16 @@ 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.reporting.ReportingManager;
import cz.cvut.fel.sit.omo.foodchain.scenario.Scenario;
import cz.cvut.fel.sit.omo.foodchain.util.ReportLogger;
import cz.cvut.fel.sit.omo.foodchain.util.Ticker;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
public class FoodChain
{
@ -23,12 +27,19 @@ public class FoodChain
public static void main(String[] args)
{
LogManager.getLogManager().reset();
Logger rootLogger = LogManager.getLogManager().getLogger("");
rootLogger.addHandler(new ReportLogger());
if(args.length < 4)
{
parseChannels("conf/channels.xml");
parseNodes("conf/nodes.xml");
parseProducts("conf/products.xml");
parseScenarios("conf/scenarios.xml");
rootLogger.log(Level.CONFIG,"Parsed default scenarios");
}
else
{
@ -36,6 +47,8 @@ public class FoodChain
parseNodes(args[2]);
parseProducts(args[3]);
parseScenarios(args[4]);
rootLogger.log(Level.CONFIG,"Parsed non-default scenarios");
}
// getFactoryManager().getPoolDatabaseInstance().getChannelPoolInstance().findAll().stream().forEach(ch -> System.out.println(ch.getProductType()));
@ -68,6 +81,7 @@ public class FoodChain
catch (ParserConfigurationException | SAXException | IOException e)
{
System.err.println(e.getMessage());
}
return ConfigurationParser.getElements(rootElementTag);

View File

@ -12,6 +12,9 @@ import cz.cvut.fel.sit.omo.foodchain.util.Observable;
import java.util.*;
import java.util.stream.Collectors;
/**
* Base class for all channels
*/
public abstract class ChannelBase implements Observable {
protected ProductType productType;
protected Queue<Requirement> requirements;
@ -46,7 +49,7 @@ public abstract class ChannelBase implements Observable {
}
/**
* Adds new requirement to the requirement Queue
* Adds new requirement to the requirement Queue.
* @param requirement requirement
*/
public void addRequirement(Requirement requirement)
@ -54,6 +57,10 @@ public abstract class ChannelBase implements Observable {
this.requirements.add(requirement);
}
/**
* Passes tick onto every requirement in channel, if requirement has TTL= 0 deletes it, notifies all nodes with current requirements.
* @return if there are any requirements
*/
public boolean tick() {
requirements.forEach(Requirement::tick);
try {
@ -64,23 +71,32 @@ public abstract class ChannelBase implements Observable {
return requirements.size() != 0;
}
/**
* Notifies all nodes apart from creator about a requirement.
*/
@Override
public void notifyAllObservers(){
subscribers.forEach(subscriber -> new LinkedList<>(requirements).forEach(r -> subscriber.update(r, this)));
}
/**
* Adds observer to list of subscribed nodes.
* @param observer channelobserver
*/
@Override
public void attach(ChannelObserver observer){
subscribers.add(observer);
}
/**
* Removes observer from list of subscribed nodes.
* @param observer channelobserver
*/
@Override
public void detach(ChannelObserver observer){
subscribers.remove(observer);
}
public void detach(ChannelObserver observer){ subscribers.remove(observer); }
/**
* Adds new transaction to the transaction Queue
* Adds new transaction to the transaction Queue.
* @param transaction transaction
*/
public void addTransaction(Transaction transaction)
@ -92,12 +108,20 @@ public abstract class ChannelBase implements Observable {
catch (Exception ignored) {}
}
/**
* Removes requirement from list of active requirements.
* @param requirement requirement
*/
public void disposeOf(Requirement requirement) { this.requirements.remove(requirement); }
/**
* Removes transaction from list of unprocessed transactions.
* @param transaction transaction
*/
public void disposeOf(Transaction transaction) { this.transactions.remove(transaction); }
/**
* Clears all requirements from this channel
* Clears all active requirements from this channel.
*/
public void clearRequirements()
{

View File

@ -1,5 +1,8 @@
package cz.cvut.fel.sit.omo.foodchain.channel;
/**
* Enum class for different subscription types
*/
public enum ChannelSubscriptionType {
SALE, PURCHASE, SALE_AND_PURCHASE

View File

@ -2,6 +2,9 @@ package cz.cvut.fel.sit.omo.foodchain.channel;
import cz.cvut.fel.sit.omo.foodchain.product.ProductType;
/**
* Channel for transporting fruit
*/
public class FruitChannel extends ChannelBase
{
public FruitChannel()

View File

@ -2,6 +2,9 @@ package cz.cvut.fel.sit.omo.foodchain.channel;
import cz.cvut.fel.sit.omo.foodchain.product.ProductType;
/**
* Channel for transporting meat
*/
public class MeatChannel extends ChannelBase
{
public MeatChannel()

View File

@ -2,6 +2,9 @@ package cz.cvut.fel.sit.omo.foodchain.channel;
import cz.cvut.fel.sit.omo.foodchain.product.ProductType;
/**
* Channel for transporting other products
*/
public class OtherChannel extends ChannelBase
{
public OtherChannel()

View File

@ -2,6 +2,9 @@ package cz.cvut.fel.sit.omo.foodchain.channel;
import cz.cvut.fel.sit.omo.foodchain.product.ProductType;
/**
* Channel for transporting vegetable
*/
public class VegetableChannel extends ChannelBase
{
public VegetableChannel()

View File

@ -2,14 +2,22 @@ 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;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Factory for creating channels
*/
public class ChannelFactory
{
private static final Logger LOGGER = Logger.getLogger(ChannelFactory.class.getName());
/**
* Creates channel based on channel type (Fruit, Vegetable, Meat, Other)
* @param input data from channel is created
* Creates channel based on channel type (Fruit, Vegetable, Meat, Other).
* @param input data from channel that is created
* @return created Channel (FruitChannel, VegetableChannel, MeatChannel, OtherChannel)
*/
public ChannelBase makeChannel(ParserResultElement input)
@ -23,15 +31,20 @@ public class ChannelFactory
}
catch (IllegalArgumentException e)
{
System.err.println("! Wrong type of enum in ChannelFactory: " + e);
LOGGER.log(Level.SEVERE, "! Wrong type of enum in ChannelFactory: " + e);
}
catch (Exception e)
{
System.err.println("! Fatal error in ChannelFactory: " + e);
LOGGER.log(Level.SEVERE, "! Fatal error in ChannelFactory: " + e);
}
return c;
}
/**
* Creates channel based on channel type (Fruit, Vegetable, Meat, Other).
* @param typeOfChannel channel type to be created
* @return created Channel (FruitChannel, VegetableChannel, MeatChannel, OtherChannel)
*/
private ChannelBase makeChannelFromChannelType(ProductType typeOfChannel)
{
switch (typeOfChannel)

View File

@ -5,6 +5,9 @@ import cz.cvut.fel.sit.omo.foodchain.util.Singleton;
import java.lang.reflect.InvocationTargetException;
/**
* Manager class for all factories and pool database
*/
public class FactoryManager
{
public NodeFactory getNodeFactoryInstance()

View File

@ -10,13 +10,18 @@ import cz.cvut.fel.sit.omo.foodchain.pool.ChannelPool;
import cz.cvut.fel.sit.omo.foodchain.product.ProductType;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Factory for creating nodes
*/
public class NodeFactory
{
private static final Logger LOGGER = Logger.getLogger(NodeFactory.class.getName());
/**
* Creates Node based on input ParserResultElement
* @param input data from Node is created
* Creates Node based on input ParserResultElement.
* @param input data from Node that is created
* @return created Node
*/
public NodeBase makeNode(ParserResultElement input)
@ -35,11 +40,11 @@ public class NodeFactory
}
catch (IllegalArgumentException e)
{
System.err.println("! Wrong type of enum in NodeFactory: " + e.getMessage());
LOGGER.log(Level.SEVERE, "! Wrong type of enum in NodeFactory: " + e.getMessage());
}
catch (Exception e)
{
System.err.println("! Fatal error in NodeFactory: " + e.getMessage());
LOGGER.log(Level.SEVERE, "! Fatal error in NodeFactory: " + e.getMessage());
}
switch (Objects.requireNonNull(nodeType))

View File

@ -5,12 +5,20 @@ 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;
import java.util.logging.Logger;
/**
* Factory for creating products
*/
public class ProductFactory
{
private static final Logger LOGGER = Logger.getLogger(ProductFactory.class.getName());
/**
* Creates Product based on input ParserResultElement
* @param input data from Product is created
* Creates Product based on input ParserResultElement.
* @param input data from Product that is created
* @return created Product
*/
public Product makeProduct(ParserResultElement input)
@ -28,11 +36,11 @@ public class ProductFactory
}
catch (IllegalArgumentException e)
{
System.err.println("! Wrong type of enum in ProductFactory: " + e);
LOGGER.log(Level.SEVERE, "! Wrong type of enum in ProductFactory: " + e.getMessage());
}
catch (Exception e)
{
System.err.println("! Fatal error in ProductFactory: " + e);
LOGGER.log(Level.SEVERE, "! Fatal error in ProductFactory: " + e.getMessage());
}
return p;
}

View File

@ -14,13 +14,18 @@ import cz.cvut.fel.sit.omo.foodchain.scenario.*;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Factory for creating scenarios
*/
public class ScenarioFactory
{
private static final Logger LOGGER = Logger.getLogger(ScenarioFactory.class.getName());
/**
* Creates Scenario based on input ParserResultElement
* @param input data from Scenario is created
* Creates Scenario based on input ParserResultElement.
* @param input data from Scenario that is created
* @return created Scenario
*/
public Scenario makeScenario(ParserResultElement input)
@ -76,7 +81,7 @@ public class ScenarioFactory
}
catch (IllegalArgumentException e)
{
System.err.println("! Wrong type of enum in ScenarioFactory: " + e);
LOGGER.log(Level.SEVERE, "! Wrong type of enum in ScenarioFactory: " + e.getMessage());
}
return s;

View File

@ -5,6 +5,9 @@ import cz.cvut.fel.sit.omo.foodchain.node.enums.NodeType;
import java.util.Random;
/**
* Customer node
*/
public class Customer extends BuyerNodeBase {
public Customer(double startMoney) {

View File

@ -3,6 +3,9 @@ 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 Distributor(double startMoney) {

View File

@ -6,7 +6,11 @@ import cz.cvut.fel.sit.omo.foodchain.operation.TransactionType;
import cz.cvut.fel.sit.omo.foodchain.product.Product;
import javax.naming.InsufficientResourcesException;
import java.util.logging.Level;
/**
* Farmer node
*/
public class Farmer extends SellerNodeBase {
public Farmer(double startMoney) {
@ -21,7 +25,7 @@ public class Farmer extends SellerNodeBase {
try {
createRequirement(TransactionType.SALE, product.getProductType(), product.getName(), product.getPrice());
} catch (InsufficientResourcesException e) {
System.err.println(e.getMessage());
LOGGER.log(Level.WARNING, e.getMessage());
}
}
}

View File

@ -3,6 +3,9 @@ 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 Processor(double startMoney) {

View File

@ -3,6 +3,9 @@ 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 Seller(double startMoney) {

View File

@ -9,6 +9,9 @@ import cz.cvut.fel.sit.omo.foodchain.product.ProductType;
import java.util.LinkedList;
import java.util.List;
/**
* Storage sub-node for storing products of other nodes
*/
public class Storage
{
private final NodeBase storageOwner;
@ -20,7 +23,7 @@ public class Storage
}
/**
* Adds provided product into the storage
* Adds provided product into the storage.
* @param product
*/
public void storeProduct(Product product)
@ -29,7 +32,7 @@ public class Storage
}
/**
* Adds all of the provided products into the storage
* Adds all of the provided products into the storage.
* @param products
*/
public void storeProducts(List<Product> products)
@ -38,7 +41,7 @@ public class Storage
}
/**
* Finds a product (first if there is multiple of them) based on its name and type
* Finds a product (first if there is multiple of them) based on its name and type.
* @param name name of product to find
* @param type type of product to find
* @return product if found, null if product is not in storage
@ -48,17 +51,13 @@ public class Storage
return products.stream().filter(ch -> ch.getProductType() == type && ch.getName().equals(name)).findFirst().orElse(null);
}
/**
* Returns List of all products in storage
* @return
*/
public List<Product> getProducts()
{
return products;
}
/**
* Returns number of products in storage
* Returns number of products in storage.
* @return
*/
public int getNumberOfStoredProducts()
@ -67,7 +66,7 @@ public class Storage
}
/**
* Checks whether storage contains provided product
* Checks whether storage contains provided product.
* @param product product to check
* @return true if contains, false if not
*/
@ -77,7 +76,7 @@ public class Storage
}
/**
* Checks whether storage contains provided product
* Checks whether storage contains provided product.
* @param name name of product to check
* @param type type of product to check
* @return true if contains, false if not
@ -88,7 +87,7 @@ public class Storage
}
/**
* Removes provided product from storage if storage contains this product. (Removes only first found)
* Removes provided product from storage if storage contains this product. (Removes only first found).
* @param product product to remove
*/
public void removeProduct(Product product)
@ -114,7 +113,7 @@ public class Storage
}
/**
* Calls specific ProductOperation on each product in stock
* Calls specific ProductOperation on each product in stock.
* @param action ProductOperationType
*/
public void doAction(ProductOperationType action)

View File

@ -3,6 +3,9 @@ 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);

View File

@ -17,9 +17,16 @@ import org.javamoney.moneta.Money;
import javax.money.MonetaryAmount;
import javax.naming.InsufficientResourcesException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Base class for all nodes
*/
public class NodeBase implements ChannelObserver {
protected static final Logger LOGGER = Logger.getLogger(NodeBase.class.getName());
private final Map<ChannelBase, ChannelSubscriptionType> subscribedChannels = new HashMap<>();
private final List<Transaction> refusedTransactions = new LinkedList<>();
private final List<RefusedRequirement> refusedRequirements = new LinkedList<>();
@ -44,6 +51,11 @@ public class NodeBase implements ChannelObserver {
}
/**
* Sends product transaction to node through a channel based on its type.
* @param product product to be sent
* @param node receiver node
*/
public void sendTransaction(Product product, NodeBase node) {
try {
Transaction transaction = new ProductTransaction(this, node, TransactionType.SALE, product);
@ -51,11 +63,17 @@ public class NodeBase implements ChannelObserver {
.filter(ch -> ch.getProductType().equals(product.getProductType()))
.findAny().ifPresent(channel -> channel.addTransaction(transaction));
} catch (InsufficientResourcesException e) {
System.err.println(e.getMessage());
LOGGER.log(Level.WARNING, e.getMessage());
}
}
/**
* Sends financial transaction to node through a channel based on previous transaction type.
* @param amount amount to be sent
* @param node receiver node
* @param prevTransaction previous product transaction
*/
public void sendTransaction(MonetaryAmount amount, NodeBase node, ProductTransaction prevTransaction) {
try {
Transaction transaction = new FinancialTransaction(this, node, TransactionType.PURCHASE, amount, prevTransaction);
@ -63,10 +81,14 @@ public class NodeBase implements ChannelObserver {
.filter(ch -> ch.getProductType().equals(prevTransaction.getProduct().getProductType()))
.findAny().ifPresent(channel -> channel.addTransaction(transaction));
} catch (InsufficientResourcesException e) {
System.err.println(e.getMessage());
LOGGER.log(Level.WARNING, e.getMessage());
}
}
/**
* Receives (processes) transaction.
* @param transaction transaction to be received
*/
public void receiveTransaction(Transaction transaction) {
try {
receiveTransaction((ProductTransaction) transaction);
@ -76,11 +98,15 @@ public class NodeBase implements ChannelObserver {
receiveTransaction((FinancialTransaction) transaction);
}
catch (Exception ex) {
System.err.println(ex.getMessage());
LOGGER.log(Level.WARNING, e.getMessage());
}
}
}
/**
* Receives (validates) product transaction and sends financial transaction as response.
* @param transaction transaction to be received
*/
public void receiveTransaction(ProductTransaction transaction) {
if (validateSignature(transaction)) {
transaction.getProduct().setStateToReadyForReception();
@ -91,29 +117,40 @@ public class NodeBase implements ChannelObserver {
else refuseTransaction(transaction);
}
/**
* Receives (validates) financial transaction.
* @param transaction transaction to be received
*/
public void receiveTransaction(FinancialTransaction transaction) {
if (validateSignature(transaction)) transaction.endTransaction();
else refuseTransaction(transaction);
}
/**
* Adds transaction to refused transactions.
* @param transaction
*/
public void refuseTransaction(Transaction transaction) {
transaction.endTransaction();
refusedTransactions.add(transaction);
}
/**
* Receives all transactions for this node.
*/
public void receiveTransactions() {
subscribedChannels.keySet().forEach(ch -> ch.getTransactions(this).forEach(t -> {receiveTransaction(t); ch.disposeOf(t);}));
}
public void createRequirement(TransactionType tType, ProductType pType, String pName, double price) {
Requirement req = new Requirement(this, tType, pType, pName, price);
subscribedChannels.keySet().stream()
.filter(ch -> ch.getProductType().equals(pType))
.findAny().ifPresent(channel -> channel.addRequirement(req));
}
/**
* Creates requirement based on data provided.
* @param tType transaction type
* @param pType product type
* @param pName product name
* @param price product price
* @throws InsufficientResourcesException if product is unavailable
*/
public void createRequirement(TransactionType tType, ProductType pType, String pName, MonetaryAmount price) throws InsufficientResourcesException {
if (price == null) {
try {
@ -139,8 +176,13 @@ public class NodeBase implements ChannelObserver {
.findAny().ifPresent(channel -> channel.addRequirement(req));
}
/**
* Accepts requirement and creates response.
* @param req requirement to be accepted
* @throws InsufficientResourcesException if product is unavailable
*/
public void acceptRequirement(Requirement req) throws InsufficientResourcesException {
System.out.println(this.nodeType.toString() + " accepted " + req.toString());
LOGGER.log(Level.INFO, this.nodeType.toString() + " accepted " + req.toString());
if (req.getTransactionType() == TransactionType.SALE) {
createRequirement(TransactionType.PURCHASE, req.getProductType(), req.getProductName(), req.getPrice());
}
@ -154,19 +196,28 @@ public class NodeBase implements ChannelObserver {
}
/**
* Adds channel to subscribed channels with correct type.
* @param channel channel to be subscribed
* @param type type of subscription
*/
public void subscribeToChannel(ChannelBase channel, ChannelSubscriptionType type) {
subscribedChannels.put(channel, type);
channel.attach(this);
}
/**
* Removes channel from subscribed channels.
* @param channel
*/
public void unsubscribeFromChannel(ChannelBase channel) {
subscribedChannels.remove(channel);
}
/**
* Proceed specific type of action on provided product if its possible. (Propagated to its storage)
* 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
*/
@ -176,7 +227,7 @@ public class NodeBase implements ChannelObserver {
}
/**
* Calls specific ProductOperation on each product in stock (Propagated to its storage)
* Calls specific ProductOperation on each product in stock (Propagated to its storage).
* @param action ProductOperationType
*/
public void doAction(ProductOperationType action)
@ -196,6 +247,7 @@ public class NodeBase implements ChannelObserver {
return money;
}
<<<<<<< HEAD
public Map<ChannelBase, ChannelSubscriptionType> getSubscribedChannels() {
return subscribedChannels;
}
@ -212,18 +264,38 @@ public class NodeBase implements ChannelObserver {
return allowedPurchaser;
}
=======
/**
* Adds amount to current assets
* @param m amount to be added
*/
>>>>>>> develop
public void addMoney(MonetaryAmount m) {
this.money = this.money.add(m);
}
/**
* Subtracts amount from current assets.
* @param m amount to be subtracted
*/
public void subtractMoney(MonetaryAmount m) {
this.money = this.money.subtract(m);
}
/**
* Validates signature on transaction.
* @param transaction transaction to be validated
* @return signature is valid
*/
public boolean validateSignature(Transaction transaction) {
return SignatureManager.validateSignature(transaction);
}
/**
* Checks if requirement creator is an allowed purchaser or allowed seller.
* @param req requirement
* @return creator is valid
*/
boolean senderPurchaserCheck(Requirement req) {
NodeType creatorType = req.getCreator().nodeType;
@ -232,6 +304,12 @@ public class NodeBase implements ChannelObserver {
((allowedPurchaser == creatorType || allowedPurchaser == NodeType.All) && req.getTransactionType() == TransactionType.PURCHASE));
}
/**
* Checks if requirement type corresponds with channel subscription type.
* @param requirement requirement
* @param channel channel
* @return requirement type corresponds with channel subscription type
*/
boolean transactionSubscriptionCheck(Requirement requirement, ChannelBase channel) {
switch (subscribedChannels.get(channel)) {
case SALE:
@ -245,6 +323,11 @@ public class NodeBase implements ChannelObserver {
return false;
}
/**
* Chacks if product is available or if node has enough money
* @param req requirement
* @return product is available or node has enough money
*/
boolean requirementCheck(Requirement req) {
Product product = storage.getProduct(req.getProductName(), req.getProductType());
return (req.getTransactionType() == TransactionType.SALE && money.isGreaterThanOrEqualTo(req.getPrice())) ||
@ -252,6 +335,11 @@ public class NodeBase implements ChannelObserver {
((product.getProductState() == ProductState.AVAILABLE) || product.getProductState() == ProductState.IN_REQUIREMENT));
}
/**
* Chacks incomming requirement.
* @param requirement requirement
* @param channel channel
*/
@Override
public void update(Requirement requirement, ChannelBase channel) {
if (senderPurchaserCheck(requirement) && transactionSubscriptionCheck(requirement, channel) && requirementCheck(requirement)) {
@ -259,14 +347,16 @@ public class NodeBase implements ChannelObserver {
acceptRequirement(requirement);
channel.disposeOf(requirement);
} catch (InsufficientResourcesException e) {
System.err.println(e.getMessage());
LOGGER.log(Level.WARNING, e.getMessage());
}
}
}
/**
* Receives transactions.
*/
public void tick() {
receiveTransactions();
//System.out.println(this.getClass().getSimpleName() + ": " + money.getNumber());
}
private static class RefusedRequirement {

View File

@ -4,6 +4,9 @@ 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);

View File

@ -3,6 +3,9 @@ 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);

View File

@ -1,5 +1,8 @@
package cz.cvut.fel.sit.omo.foodchain.node.enums;
/**
* Enum class for all nodes
*/
public enum NodeType {
Farmer, Processor, Distributor, Seller, Customer, None, All
}

View File

@ -2,6 +2,9 @@ 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);

View File

@ -2,6 +2,9 @@ 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);

View File

@ -3,8 +3,13 @@ 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.product.Product;
public class Action extends OperationBase {
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Operation for processing products in storage
*/
public class Action extends OperationBase {
private final OperationBase lastOperation;
private final Product product;
private final ProductOperationType type;
@ -18,14 +23,22 @@ public class Action extends OperationBase {
duration = type.getDuration();
product.setCurrentOperation(this);
product.setStateToInAction();
System.out.println(toString());
LOGGER.log(Level.INFO, toString());
}
/**
* Ends this action and changes products type to available.
*/
private void endAction() {
this.setTimeEnd();
product.setStateToAvailable();
}
/**
* Changes actions duration or ends action.
* @return action is in progress
*/
public boolean tick() {
if (duration == 0) {
endAction();

View File

@ -5,7 +5,11 @@ import cz.cvut.fel.sit.omo.foodchain.reporting.ReportTextVisitor;
import javax.money.MonetaryAmount;
import javax.naming.InsufficientResourcesException;
import java.util.logging.Level;
/**
* Operation for transporting money
*/
public class FinancialTransaction extends Transaction {
private final MonetaryAmount amount;
@ -17,9 +21,13 @@ public class FinancialTransaction extends Transaction {
this.transactionPaid = transactionPaid;
if (creator.getMoney().isLessThan(amount)) throw new InsufficientResourcesException("not enough money");
creator.subtractMoney(amount);
System.out.println(toString());
LOGGER.log(Level.INFO, toString());
}
/**
* Ends transaction and adds amount to receiver node.
*/
@Override
public void endTransaction() {
super.endTransaction();

View File

@ -1,11 +1,18 @@
package cz.cvut.fel.sit.omo.foodchain.operation;
import cz.cvut.fel.sit.omo.foodchain.factory.ScenarioFactory;
import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase;
import java.time.LocalDateTime;
import java.util.logging.Logger;
/**
* Base class for all operations
*/
public abstract class OperationBase {
protected static final Logger LOGGER = Logger.getLogger(OperationBase.class.getName());
private final LocalDateTime timeStart;
private LocalDateTime timeEnd;

View File

@ -3,6 +3,9 @@ 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.product.ProductType;
/**
* Enum class for product operations types with parameters
*/
public enum ProductOperationType
{
STORE_MEAT(NodeType.All, ProductType.MEAT, 20, -8),

View File

@ -6,7 +6,11 @@ import cz.cvut.fel.sit.omo.foodchain.product.ProductState;
import cz.cvut.fel.sit.omo.foodchain.reporting.ReportTextVisitor;
import javax.naming.InsufficientResourcesException;
import java.util.logging.Level;
/**
* Operation for transporting products
*/
public class ProductTransaction extends Transaction {
private final OperationBase lastOperation;
@ -22,9 +26,13 @@ public class ProductTransaction extends Transaction {
product.setCurrentOperation(this);
product.setStateToReadyForDispatch();
creator.getStorage().removeProduct(product);
System.out.println(toString());
LOGGER.log(Level.INFO, toString());
}
/**
* Ends transaction and stores product in receivers storage.
*/
@Override
public void endTransaction() {
super.endTransaction();

View File

@ -5,6 +5,9 @@ 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;
/**
* Operation for transporting things between nodes
*/
public abstract class Transaction extends OperationBase {
private final TransactionType transactionType;
@ -18,6 +21,9 @@ public abstract class Transaction extends OperationBase {
signature = SignatureManager.signTransaction(this);
}
/**
* Sets time end to current time.
*/
public void endTransaction() {
this.setTimeEnd();
}

View File

@ -1,5 +1,8 @@
package cz.cvut.fel.sit.omo.foodchain.operation;
/**
* Enum class for transaction types
*/
public enum TransactionType {
SALE, PURCHASE

View File

@ -11,10 +11,20 @@ import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
/**
* Parser for XML configuration
*/
public class ConfigurationParser {
private static Document activeDocument;
/**
* Parses xml file to document.
* @param name file name
* @throws ParserConfigurationException ParserConfigurationException
* @throws IOException IOException
* @throws SAXException SAXException
*/
public static void parseDocument(String name) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(true);
@ -24,6 +34,11 @@ public class ConfigurationParser {
activeDocument = builder.parse(file);
}
/**
* Returns parsed result with all elements having provided tag.
* @param tag element tag
* @return parsed result element
*/
public static ParserResult getElements(String tag) {
NodeList elements = activeDocument.getElementsByTagName(tag);
ParserResult resultList = new ParserResult();

View File

@ -1,4 +1,7 @@
package cz.cvut.fel.sit.omo.foodchain.parser;
/**
* Parser for console input
*/
public class ConsoleParser {
}

View File

@ -3,6 +3,9 @@ package cz.cvut.fel.sit.omo.foodchain.parser;
import java.util.LinkedList;
import java.util.List;
/**
* Wrapper class for parser result elements
*/
public class ParserResult {
private final List<ParserResultElement> elements;
@ -11,6 +14,10 @@ public class ParserResult {
elements = new LinkedList<>();
}
/**
* Adds element to list.
* @param element element
*/
public void addElement(ParserResultElement element) {
elements.add(element);
}

View File

@ -4,6 +4,9 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
/**
* Class for storing all information given in a xml tag
*/
public class ParserResultElement {
private String name;

View File

@ -3,8 +3,16 @@ package cz.cvut.fel.sit.omo.foodchain.pool;
import cz.cvut.fel.sit.omo.foodchain.channel.ChannelBase;
import cz.cvut.fel.sit.omo.foodchain.product.ProductType;
/**
* Pool for storing all channels
*/
public class ChannelPool extends PoolListBase<ChannelBase> {
/**
* Finds channel by its type.
* @param type type of channel
* @return channel
*/
public ChannelBase findByType(ProductType type) {
return findAll().stream().filter(ch -> ch.getProductType().equals(type)).findFirst().orElse(null);
}

View File

@ -2,5 +2,8 @@ package cz.cvut.fel.sit.omo.foodchain.pool;
import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase;
/**
*Pool for storing all nodes
*/
public class NodePool extends PoolListBase<NodeBase> {
}

View File

@ -4,6 +4,9 @@ import cz.cvut.fel.sit.omo.foodchain.util.Singleton;
import java.lang.reflect.InvocationTargetException;
/**
* Database class for storing all pools
*/
public class PoolDatabase {
public ChannelPool getChannelPoolInstance() {

View File

@ -3,6 +3,10 @@ package cz.cvut.fel.sit.omo.foodchain.pool;
import java.util.LinkedList;
import java.util.List;
/**
* Base class for all pools
* @param <T> pool type
*/
public abstract class PoolListBase<T> {
List<T> pool;

View File

@ -2,5 +2,8 @@ package cz.cvut.fel.sit.omo.foodchain.pool;
import cz.cvut.fel.sit.omo.foodchain.product.Product;
/**
* Pool for storing all products
*/
public class ProductPool extends PoolListBase<Product> {
}

View File

@ -2,5 +2,8 @@ package cz.cvut.fel.sit.omo.foodchain.pool;
import cz.cvut.fel.sit.omo.foodchain.scenario.Scenario;
/**
* Pool for storing all scenarios
*/
public class ScenarioPool extends PoolListBase<Scenario> {
}

View File

@ -7,6 +7,9 @@ import org.javamoney.moneta.Money;
import javax.money.MonetaryAmount;
/**
* Product class
*/
public class Product
{
private ProductState productState;
@ -16,19 +19,6 @@ public class Product
private String name;
/**
* Creates Product with default state AVAILABLE
* @param name name of product
* @param productType type of product
*/
public Product(String name, ProductType productType)
{
this.name = name;
this.productType = productType;
this.productState = ProductState.AVAILABLE;
this.price = Money.of(0, "USD");
}
public Product(String name, ProductType productType, double m)
{
this.name = name;
@ -38,27 +28,9 @@ public class Product
}
/**
* Creates Product
* @param name name of product
* @param productType type of product
* @param productState state of product
* Passes tick onto current operation
* @return operation is active
*/
public Product(String name, ProductType productType, ProductState productState)
{
this.name = name;
this.productType = productType;
this.productState = productState;
this.price = Money.of(0, "USD");
}
public Product(String name, ProductType productType, ProductState productState, double m)
{
this.name = name;
this.productType = productType;
this.productState = productState;
this.price = Money.of(m, "USD");
}
public boolean tick() {
try {
return ((Action) currentOperation).tick();
@ -138,13 +110,6 @@ public class Product
throw new IllegalStateException("Cannot set state IN_REQUIREMENT. Product is not AVAILABLE!");
}
/*
public void setProductState(ProductState productState)
{
this.productState = productState;
}*/
//Getters & Setters
public ProductState getProductState()

View File

@ -1,5 +1,8 @@
package cz.cvut.fel.sit.omo.foodchain.product;
/**
* Enum class for product states
*/
public enum ProductState
{
AVAILABLE, READY_FOR_DISPATCH, IN_TRANSIT, READY_FOR_RECEPTION, IN_ACTION, IN_REQUIREMENT

View File

@ -1,5 +1,8 @@
package cz.cvut.fel.sit.omo.foodchain.product;
/**
* Enum class for product types
*/
public enum ProductType
{
MEAT, FRUIT, VEGETABLE, OTHER, ALL // ALL is used only for actions

View File

@ -4,12 +4,19 @@ import cz.cvut.fel.sit.omo.foodchain.node.base.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;
/**
* Requirement class
*/
public class Requirement {
private static final Logger LOGGER = Logger.getLogger(Ticker.class.getName());
private final NodeBase creator;
private final TransactionType transactionType;
@ -20,17 +27,6 @@ public class Requirement {
private static int counter;
private int id;
public Requirement(NodeBase creator, TransactionType transactionType, ProductType productType, String productName, double price) {
this.creator = creator;
this.transactionType = transactionType;
this.productType = productType;
this.productName = productName;
this.price = Money.of(price, "USD");
this.TTL = 3;
this.id = counter++;
System.out.println(toString());
}
public Requirement(NodeBase creator, TransactionType transactionType, ProductType productType, String productName, MonetaryAmount price) {
this.creator = creator;
this.transactionType = transactionType;
@ -39,9 +35,14 @@ public class Requirement {
this.price = price;
this.TTL = 3;
this.id = counter++;
System.out.println(toString());
LOGGER.log(Level.INFO, toString());
}
/**
* Reduces TTL.
*/
public void tick() {
TTL--;
}

View File

@ -2,6 +2,9 @@ package cz.cvut.fel.sit.omo.foodchain.scenario;
import cz.cvut.fel.sit.omo.foodchain.node.Customer;
/**
* Step for consuming random product from storage
*/
public class ConsumeProductStep extends ScenarioStep {
private final Customer node;
@ -10,6 +13,9 @@ public class ConsumeProductStep extends ScenarioStep {
this.node = node;
}
/**
* Consumes random product.
*/
@Override
void execute() {
node.consumeProduct();

View File

@ -4,6 +4,11 @@ import cz.cvut.fel.sit.omo.foodchain.node.base.NodeBase;
import cz.cvut.fel.sit.omo.foodchain.operation.ProductOperationType;
import cz.cvut.fel.sit.omo.foodchain.product.Product;
import java.util.logging.Level;
/**
* Step for starting action on product(s)
*/
public class DoActionStep extends ScenarioStep {
private final NodeBase nodeBase;
private final ProductOperationType productOperationType;
@ -20,6 +25,9 @@ public class DoActionStep extends ScenarioStep {
}
/**
* Starts action.
*/
@Override
void execute() {
try {
@ -31,7 +39,7 @@ public class DoActionStep extends ScenarioStep {
}
}
catch (IllegalCallerException e) {
System.err.println(e.getMessage());
LOGGER.log(Level.SEVERE, e.getMessage());
}
}
}

View File

@ -4,6 +4,11 @@ import cz.cvut.fel.sit.omo.foodchain.FoodChain;
import cz.cvut.fel.sit.omo.foodchain.node.Farmer;
import cz.cvut.fel.sit.omo.foodchain.product.Product;
import java.util.logging.Level;
/**
* Step for generating product from pool
*/
public class GenerateProductStep extends ScenarioStep {
private final Farmer node;
@ -18,10 +23,13 @@ public class GenerateProductStep extends ScenarioStep {
}
else {
product = null;
System.err.println("Insufficient products in pool");
LOGGER.log(Level.SEVERE, "Insufficient products in pool");
}
}
/**
* Generates product from pool.
*/
@Override
void execute() {
node.generateProduct(product);

View File

@ -1,7 +1,13 @@
package cz.cvut.fel.sit.omo.foodchain.scenario;
/**
* Step for skipping
*/
public class PassStep extends ScenarioStep {
/**
* Does nothing.
*/
@Override
void execute() {}
}

View File

@ -3,28 +3,34 @@ package cz.cvut.fel.sit.omo.foodchain.scenario;
import java.util.Iterator;
import java.util.List;
/**
* Scenatio class fpr holding and executing steps
*/
public class Scenario {
List<ScenarioStep> steps;
Iterator<ScenarioStep> stepIterator;
public Scenario() {
stepIterator = steps.listIterator(0);
}
public Scenario(List<ScenarioStep> steps) {
this.steps = steps;
stepIterator = steps.listIterator(0);
}
/**
* Executes next step.
* @return scenario has steps
*/
boolean execute() {
if (!stepIterator.hasNext()) {
// stepIterator = steps.listIterator(0);
return false;
}
stepIterator.next().execute();
return true;
}
/**
* Executes next step.
* @return scenario has steps
*/
public boolean tick() {
return execute();
}

View File

@ -1,5 +1,14 @@
package cz.cvut.fel.sit.omo.foodchain.scenario;
import cz.cvut.fel.sit.omo.foodchain.operation.OperationBase;
import java.util.logging.Logger;
/**
* Scenario step class
*/
public abstract class ScenarioStep {
protected static final Logger LOGGER = Logger.getLogger(ScenarioStep.class.getName());
abstract void execute();
}

View File

@ -7,7 +7,11 @@ import org.javamoney.moneta.Money;
import javax.money.MonetaryAmount;
import javax.naming.InsufficientResourcesException;
import java.util.logging.Level;
/**
* Step for sending requirements
*/
public class SendRequirementStep extends ScenarioStep {
private final NodeBase node;
private final TransactionType tType;
@ -33,12 +37,15 @@ public class SendRequirementStep extends ScenarioStep {
this.pPrice = Money.of(price, "USD");
}
/**
* Creates requirement.
*/
@Override
void execute() {
try {
node.createRequirement(tType, pType, pName, pPrice);
} catch (InsufficientResourcesException e) {
System.err.println(e.getMessage());
LOGGER.log(Level.SEVERE, e.getMessage());
}
}
}

View File

@ -5,6 +5,9 @@ import cz.cvut.fel.sit.omo.foodchain.operation.Transaction;
import java.time.LocalDateTime;
import java.util.UUID;
/**
* Signature class validating its transaction
*/
public class Signature {
private final String managerCode;

View File

@ -2,14 +2,27 @@ package cz.cvut.fel.sit.omo.foodchain.signature;
import cz.cvut.fel.sit.omo.foodchain.operation.Transaction;
/**
* Manager class for creating and validating signatures
*/
public class SignatureManager {
private static final String MANAGER_CODE = "iW91AJWNOCmX1pbpLlW0";
/**
* Creates signature for transaction.
* @param transaction transaction
* @return signature
*/
public static Signature signTransaction(Transaction transaction) {
return new Signature(MANAGER_CODE, transaction);
}
/**
* Check if signature corresponds with its transaction.
* @param transaction transaction
* @return signature corresponds with its transaction
*/
public static boolean validateSignature(Transaction transaction) {
return transaction.equals(transaction.getSignature().getTransaction(MANAGER_CODE))
&& transaction.getSignature().getUuid(MANAGER_CODE).equals(transaction.getSignature().getTransaction(MANAGER_CODE).getSignature().getUuid(MANAGER_CODE));

View File

@ -3,6 +3,9 @@ package cz.cvut.fel.sit.omo.foodchain.util;
import cz.cvut.fel.sit.omo.foodchain.channel.ChannelBase;
import cz.cvut.fel.sit.omo.foodchain.requirement.Requirement;
/**
* Interface for nodes that receives requirements
*/
public interface ChannelObserver {
void update(Requirement requirement, ChannelBase channel);
}

View File

@ -1,5 +1,8 @@
package cz.cvut.fel.sit.omo.foodchain.util;
/**
* Interface for channels to work with observers
*/
public interface Observable {
void attach(ChannelObserver channelObserver);
void detach(ChannelObserver channelObserver);

View File

@ -0,0 +1,37 @@
package cz.cvut.fel.sit.omo.foodchain.util;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
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());
if(record.getLevel().equals(Level.WARNING) || record.getLevel().equals(Level.SEVERE))
{
System.err.println(sb.toString());
//todo add some outprint to report log
}
else
{
System.out.println(sb.toString());
//todo add some outprint to report log
}
}
@Override
public void flush() {
}
@Override
public void close() throws SecurityException {
}
}

View File

@ -5,6 +5,9 @@ import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
/**
* Singleton implementation 1 of 3
*/
public class Singleton {
private static final Singleton instance = new Singleton();

View File

@ -2,19 +2,30 @@ 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;
import javax.swing.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Creates artificial time for application
*/
public class Ticker {
protected static final Logger LOGGER = Logger.getLogger(Ticker.class.getName());
private static Timer timer;
/**
* Starts timer.
*/
public static void start() {
timer = new Timer(1000, actionEvent -> {
System.out.println("-----tick-----");
LOGGER.log(Level.INFO, "-----tick-----");
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
@ -25,6 +36,9 @@ public class Ticker {
timer.start();
}
/**
* Stops timer (ends application).
*/
public static void stop() {
timer.stop();
}