diff --git a/src/main/java/core/basesyntax/HelloWorld.java b/src/main/java/core/basesyntax/HelloWorld.java deleted file mode 100644 index 97db782bf7..0000000000 --- a/src/main/java/core/basesyntax/HelloWorld.java +++ /dev/null @@ -1,8 +0,0 @@ -package core.basesyntax; - -/** - * Feel free to remove this class and create your own. - */ -public class HelloWorld { - -} diff --git a/src/main/java/core/basesyntax/Main.java b/src/main/java/core/basesyntax/Main.java new file mode 100644 index 0000000000..588cf3c588 --- /dev/null +++ b/src/main/java/core/basesyntax/Main.java @@ -0,0 +1,49 @@ +package core.basesyntax; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.dao.StorageDaoImpl; +import core.basesyntax.model.Operation; +import core.basesyntax.service.DataProcessing; +import core.basesyntax.service.DataReader; +import core.basesyntax.service.OperationHandler; +import core.basesyntax.service.ReportCreator; +import core.basesyntax.service.Writer; +import core.basesyntax.service.handler.impl.BalanceOperationHandler; +import core.basesyntax.service.handler.impl.PurchaseOperationHandler; +import core.basesyntax.service.handler.impl.ReturnOperationHandler; +import core.basesyntax.service.handler.impl.SupplyOperationHandler; +import core.basesyntax.service.impl.CsvWriter; +import core.basesyntax.service.impl.DataProcessingImpl; +import core.basesyntax.service.impl.DataReaderFromCsv; +import core.basesyntax.service.impl.FruitShopServiceImpl; +import core.basesyntax.service.impl.ReportCreatorImpl; +import core.basesyntax.strategy.OperationStrategy; +import core.basesyntax.strategy.impl.OperationStrategyImpl; +import java.util.HashMap; +import java.util.Map; + +public class Main { + private static final String FILE_FROM = "src/main/resources/data.csv"; + private static final String FILE_TO = "src/main/resources/report.csv"; + + public static void main(String[] args) { + StorageDao storageDao = new StorageDaoImpl(); + Map operationHandlerMap = new HashMap<>(); + operationHandlerMap.put(Operation.BALANCE, + new BalanceOperationHandler(storageDao)); + operationHandlerMap.put(Operation.SUPPLY, + new SupplyOperationHandler(storageDao)); + operationHandlerMap.put(Operation.PURCHASE, + new PurchaseOperationHandler(storageDao)); + operationHandlerMap.put(Operation.RETURN, + new ReturnOperationHandler(storageDao)); + OperationStrategy operationStrategy = new OperationStrategyImpl(operationHandlerMap); + DataReader dataReader = new DataReaderFromCsv(); + DataProcessing dataProcessing = new DataProcessingImpl(operationStrategy); + ReportCreator reportCreator = new ReportCreatorImpl(storageDao); + Writer writer = new CsvWriter(); + FruitShopServiceImpl fruitShopService = new FruitShopServiceImpl(dataReader, + dataProcessing, reportCreator, writer); + fruitShopService.createDailyReport(FILE_FROM, FILE_TO); + } +} diff --git a/src/main/java/core/basesyntax/dao/StorageDao.java b/src/main/java/core/basesyntax/dao/StorageDao.java new file mode 100644 index 0000000000..4ef360f96c --- /dev/null +++ b/src/main/java/core/basesyntax/dao/StorageDao.java @@ -0,0 +1,14 @@ +package core.basesyntax.dao; + +import core.basesyntax.model.Fruit; +import java.util.Map; + +public interface StorageDao { + void add(Fruit fruit, Integer amount); + + Map.Entry get(String name); + + boolean isInStorage(String name); + + Map getALl(); +} diff --git a/src/main/java/core/basesyntax/dao/StorageDaoImpl.java b/src/main/java/core/basesyntax/dao/StorageDaoImpl.java new file mode 100644 index 0000000000..d4261fe032 --- /dev/null +++ b/src/main/java/core/basesyntax/dao/StorageDaoImpl.java @@ -0,0 +1,32 @@ +package core.basesyntax.dao; + +import core.basesyntax.db.Storage; +import core.basesyntax.model.Fruit; +import java.util.HashMap; +import java.util.Map; + +public class StorageDaoImpl implements StorageDao { + @Override + public void add(Fruit fruit, Integer amount) { + Storage.fruits.put(fruit, amount); + } + + @Override + public Map.Entry get(String name) { + for (Map.Entry entry : Storage.fruits.entrySet()) { + if (entry.getKey().getName().equals(name)) { + return entry; + } + } + return null; + } + + public boolean isInStorage(String name) { + return (get(name) != null); + } + + @Override + public Map getALl() { + return new HashMap<>(Storage.fruits); + } +} diff --git a/src/main/java/core/basesyntax/db/Storage.java b/src/main/java/core/basesyntax/db/Storage.java new file mode 100644 index 0000000000..94c4799415 --- /dev/null +++ b/src/main/java/core/basesyntax/db/Storage.java @@ -0,0 +1,9 @@ +package core.basesyntax.db; + +import core.basesyntax.model.Fruit; +import java.util.HashMap; +import java.util.Map; + +public class Storage { + public static final Map fruits = new HashMap<>(); +} diff --git a/src/main/java/core/basesyntax/model/Fruit.java b/src/main/java/core/basesyntax/model/Fruit.java new file mode 100644 index 0000000000..1ccbedec9a --- /dev/null +++ b/src/main/java/core/basesyntax/model/Fruit.java @@ -0,0 +1,41 @@ +package core.basesyntax.model; + +import java.util.Objects; + +public class Fruit { + private String name; + + public Fruit(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Fruit fruit = (Fruit) o; + return Objects.equals(name, fruit.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + @Override + public String toString() { + return "Fruit{" + "name='" + name + '\'' + '}'; + } +} diff --git a/src/main/java/core/basesyntax/model/FruitTransaction.java b/src/main/java/core/basesyntax/model/FruitTransaction.java new file mode 100644 index 0000000000..b04c9cf1b6 --- /dev/null +++ b/src/main/java/core/basesyntax/model/FruitTransaction.java @@ -0,0 +1,31 @@ +package core.basesyntax.model; + +public class FruitTransaction { + private Operation operation; + private String fruitName; + private int amount; + + public Operation getOperation() { + return operation; + } + + public void setOperation(Operation operation) { + this.operation = operation; + } + + public String getFruitName() { + return fruitName; + } + + public void setFruitName(String fruit) { + this.fruitName = fruit; + } + + public int getAmount() { + return amount; + } + + public void setAmount(int amount) { + this.amount = amount; + } +} diff --git a/src/main/java/core/basesyntax/model/Operation.java b/src/main/java/core/basesyntax/model/Operation.java new file mode 100644 index 0000000000..bf8bd8a614 --- /dev/null +++ b/src/main/java/core/basesyntax/model/Operation.java @@ -0,0 +1,28 @@ +package core.basesyntax.model; + +import java.util.Arrays; + +public enum Operation { + BALANCE("b"), + SUPPLY("s"), + PURCHASE("p"), + RETURN("r"); + + private String code; + + Operation(String code) { + this.code = code; + } + + public String getCodeOfOperation() { + return code; + } + + public static Operation getOperationOf(String letter) { + return Arrays.stream(Operation.values()) + .filter(o -> o.getCodeOfOperation().equals(letter)) + .findFirst() + .orElseThrow(() -> new RuntimeException("There is no such operation by letter " + + "'" + letter + "'")); + } +} diff --git a/src/main/java/core/basesyntax/service/DataProcessing.java b/src/main/java/core/basesyntax/service/DataProcessing.java new file mode 100644 index 0000000000..1375df05ff --- /dev/null +++ b/src/main/java/core/basesyntax/service/DataProcessing.java @@ -0,0 +1,7 @@ +package core.basesyntax.service; + +import java.util.List; + +public interface DataProcessing { + void processTransaction(List data); +} diff --git a/src/main/java/core/basesyntax/service/DataReader.java b/src/main/java/core/basesyntax/service/DataReader.java new file mode 100644 index 0000000000..e09492732d --- /dev/null +++ b/src/main/java/core/basesyntax/service/DataReader.java @@ -0,0 +1,8 @@ +package core.basesyntax.service; + +import java.util.List; + +public interface DataReader { + List readData(String file); + +} diff --git a/src/main/java/core/basesyntax/service/OperationHandler.java b/src/main/java/core/basesyntax/service/OperationHandler.java new file mode 100644 index 0000000000..8898a2d365 --- /dev/null +++ b/src/main/java/core/basesyntax/service/OperationHandler.java @@ -0,0 +1,16 @@ +package core.basesyntax.service; + +import core.basesyntax.model.FruitTransaction; + +public interface OperationHandler { + int MIN_AMOUNT = 0; + + void updateStorage(FruitTransaction transaction); + + default void validAmount(FruitTransaction transaction) { + if (transaction.getAmount() < MIN_AMOUNT) { + throw new RuntimeException("OPERATION " + transaction.getOperation() + + "! Amount is less then zero!!!"); + } + } +} diff --git a/src/main/java/core/basesyntax/service/ReportCreator.java b/src/main/java/core/basesyntax/service/ReportCreator.java new file mode 100644 index 0000000000..54e05395c7 --- /dev/null +++ b/src/main/java/core/basesyntax/service/ReportCreator.java @@ -0,0 +1,5 @@ +package core.basesyntax.service; + +public interface ReportCreator { + String createReport(); +} diff --git a/src/main/java/core/basesyntax/service/Writer.java b/src/main/java/core/basesyntax/service/Writer.java new file mode 100644 index 0000000000..2c12c7dfef --- /dev/null +++ b/src/main/java/core/basesyntax/service/Writer.java @@ -0,0 +1,5 @@ +package core.basesyntax.service; + +public interface Writer { + void writeReportToFile(String report, String toFile); +} diff --git a/src/main/java/core/basesyntax/service/handler/impl/BalanceOperationHandler.java b/src/main/java/core/basesyntax/service/handler/impl/BalanceOperationHandler.java new file mode 100644 index 0000000000..ad1cd4128d --- /dev/null +++ b/src/main/java/core/basesyntax/service/handler/impl/BalanceOperationHandler.java @@ -0,0 +1,25 @@ +package core.basesyntax.service.handler.impl; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.model.Fruit; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.OperationHandler; + +public class BalanceOperationHandler implements OperationHandler { + private final StorageDao storageDao; + + public BalanceOperationHandler(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public void updateStorage(FruitTransaction transaction) { + validAmount(transaction); + if (!storageDao.isInStorage(transaction.getFruitName())) { + storageDao.add(new Fruit(transaction.getFruitName()), transaction.getAmount()); + } else { + storageDao.get(transaction.getFruitName()).setValue(transaction.getAmount()); + } + } + +} diff --git a/src/main/java/core/basesyntax/service/handler/impl/PurchaseOperationHandler.java b/src/main/java/core/basesyntax/service/handler/impl/PurchaseOperationHandler.java new file mode 100644 index 0000000000..c7f22ad222 --- /dev/null +++ b/src/main/java/core/basesyntax/service/handler/impl/PurchaseOperationHandler.java @@ -0,0 +1,36 @@ +package core.basesyntax.service.handler.impl; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.model.Fruit; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.OperationHandler; +import java.util.Map; + +public class PurchaseOperationHandler implements OperationHandler { + private final StorageDao storageDao; + + public PurchaseOperationHandler(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public void updateStorage(FruitTransaction transaction) { + validAmountOfFruit(transaction); + Map.Entry fruitAndAmount = storageDao.get(transaction.getFruitName()); + Integer fruitAmount = fruitAndAmount.getValue(); + Integer fruitAmountFromTransaction = transaction.getAmount(); + fruitAndAmount.setValue(fruitAmount - fruitAmountFromTransaction); + + } + + private void validAmountOfFruit(FruitTransaction transaction) { + validAmount(transaction); + if (!storageDao.isInStorage(transaction.getFruitName())) { + throw new RuntimeException("There is no such fruit!!!"); + } + if (storageDao.get(transaction.getFruitName()).getValue() < transaction.getAmount()) { + throw new RuntimeException("Amount of " + transaction.getFruitName() + + " isn't enough!!!"); + } + } +} diff --git a/src/main/java/core/basesyntax/service/handler/impl/ReturnOperationHandler.java b/src/main/java/core/basesyntax/service/handler/impl/ReturnOperationHandler.java new file mode 100644 index 0000000000..6f8dc53fee --- /dev/null +++ b/src/main/java/core/basesyntax/service/handler/impl/ReturnOperationHandler.java @@ -0,0 +1,28 @@ +package core.basesyntax.service.handler.impl; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.model.Fruit; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.OperationHandler; +import java.util.Map; + +public class ReturnOperationHandler implements OperationHandler { + private final StorageDao storageDao; + + public ReturnOperationHandler(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public void updateStorage(FruitTransaction transaction) { + validAmount(transaction); + if (!storageDao.isInStorage(transaction.getFruitName())) { + storageDao.add(new Fruit(transaction.getFruitName()), transaction.getAmount()); + } else { + Map.Entry fruitAndAmount = storageDao.get(transaction.getFruitName()); + Integer fruitAmount = fruitAndAmount.getValue(); + Integer fruitAmountFromTransaction = transaction.getAmount(); + fruitAndAmount.setValue(fruitAmount + fruitAmountFromTransaction); + } + } +} diff --git a/src/main/java/core/basesyntax/service/handler/impl/SupplyOperationHandler.java b/src/main/java/core/basesyntax/service/handler/impl/SupplyOperationHandler.java new file mode 100644 index 0000000000..ac3874141a --- /dev/null +++ b/src/main/java/core/basesyntax/service/handler/impl/SupplyOperationHandler.java @@ -0,0 +1,28 @@ +package core.basesyntax.service.handler.impl; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.model.Fruit; +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.service.OperationHandler; +import java.util.Map; + +public class SupplyOperationHandler implements OperationHandler { + private final StorageDao storageDao; + + public SupplyOperationHandler(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public void updateStorage(FruitTransaction transaction) { + validAmount(transaction); + if (!storageDao.isInStorage(transaction.getFruitName())) { + storageDao.add(new Fruit(transaction.getFruitName()), transaction.getAmount()); + } else { + Map.Entry fruitAndAmount = storageDao.get(transaction.getFruitName()); + Integer fruitAmount = fruitAndAmount.getValue(); + Integer fruitAmountFromTransaction = transaction.getAmount(); + fruitAndAmount.setValue(fruitAmount + fruitAmountFromTransaction); + } + } +} diff --git a/src/main/java/core/basesyntax/service/impl/CsvWriter.java b/src/main/java/core/basesyntax/service/impl/CsvWriter.java new file mode 100644 index 0000000000..ed8ffe163b --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/CsvWriter.java @@ -0,0 +1,17 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.service.Writer; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class CsvWriter implements Writer { + @Override + public void writeReportToFile(String report, String toFile) { + try { + Files.write(Path.of(toFile), report.getBytes()); + } catch (IOException e) { + throw new RuntimeException("Can't write data to file" + toFile); + } + } +} diff --git a/src/main/java/core/basesyntax/service/impl/DataProcessingImpl.java b/src/main/java/core/basesyntax/service/impl/DataProcessingImpl.java new file mode 100644 index 0000000000..ddc262db30 --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/DataProcessingImpl.java @@ -0,0 +1,44 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.model.FruitTransaction; +import core.basesyntax.model.Operation; +import core.basesyntax.service.DataProcessing; +import core.basesyntax.strategy.OperationStrategy; +import java.util.List; + +public class DataProcessingImpl implements DataProcessing { + private static final String SPLITERATOR = ","; + private static final int OPERATION_POSITION = 0; + private static final int FRUIT_NAME_POSITION = 1; + private static final int AMOUNT_OF_FRUIT_POSITION = 2; + private final OperationStrategy operationStrategy; + + public DataProcessingImpl(OperationStrategy operationStrategy) { + this.operationStrategy = operationStrategy; + } + + @Override + public void processTransaction(List data) { + List fruitTransactions = getFruitTransactions(data); + fruitTransactions + .forEach(t -> operationStrategy.getOperationHandler(t.getOperation()) + .updateStorage(t)); + } + + private List getFruitTransactions(List data) { + return data.stream() + .map(this::getTransactionFromRow) + .toList(); + } + + private FruitTransaction getTransactionFromRow(String line) { + FruitTransaction fruitTransaction = new FruitTransaction(); + String[] rowWithTransaction = line.split(SPLITERATOR); + fruitTransaction.setOperation(Operation.getOperationOf( + rowWithTransaction[OPERATION_POSITION].trim())); + fruitTransaction.setFruitName(rowWithTransaction[FRUIT_NAME_POSITION].trim()); + fruitTransaction.setAmount(Integer + .parseInt(rowWithTransaction[AMOUNT_OF_FRUIT_POSITION].trim())); + return fruitTransaction; + } +} diff --git a/src/main/java/core/basesyntax/service/impl/DataReaderFromCsv.java b/src/main/java/core/basesyntax/service/impl/DataReaderFromCsv.java new file mode 100644 index 0000000000..d25ee8f17f --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/DataReaderFromCsv.java @@ -0,0 +1,22 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.service.DataReader; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.List; + +public class DataReaderFromCsv implements DataReader { + private static final int ROW_TO_SKIP = 1; + + @Override + public List readData(String file) { + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + return reader.lines() + .skip(ROW_TO_SKIP) + .toList(); + } catch (IOException e) { + throw new RuntimeException("Can't read data from file" + file); + } + } +} diff --git a/src/main/java/core/basesyntax/service/impl/FruitShopServiceImpl.java b/src/main/java/core/basesyntax/service/impl/FruitShopServiceImpl.java new file mode 100644 index 0000000000..89b4cc5f89 --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/FruitShopServiceImpl.java @@ -0,0 +1,30 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.service.DataProcessing; +import core.basesyntax.service.DataReader; +import core.basesyntax.service.ReportCreator; +import core.basesyntax.service.Writer; +import java.util.List; + +public class FruitShopServiceImpl { + private final DataReader dataReader; + private final DataProcessing dataProcessing; + private final ReportCreator reportCreator; + private final Writer writer; + + public FruitShopServiceImpl(DataReader dataReader, DataProcessing dataProcessing, + ReportCreator reportCreator, Writer writer) { + this.dataReader = dataReader; + this.dataProcessing = dataProcessing; + this.reportCreator = reportCreator; + this.writer = writer; + } + + public void createDailyReport(String fromFile, String toFile) { + List dataFromFile = dataReader.readData(fromFile); + dataProcessing.processTransaction(dataFromFile); + String report = reportCreator.createReport(); + writer.writeReportToFile(report, toFile); + } + +} diff --git a/src/main/java/core/basesyntax/service/impl/ReportCreatorImpl.java b/src/main/java/core/basesyntax/service/impl/ReportCreatorImpl.java new file mode 100644 index 0000000000..fb3a06adb9 --- /dev/null +++ b/src/main/java/core/basesyntax/service/impl/ReportCreatorImpl.java @@ -0,0 +1,24 @@ +package core.basesyntax.service.impl; + +import core.basesyntax.dao.StorageDao; +import core.basesyntax.service.ReportCreator; +import java.util.stream.Collectors; + +public class ReportCreatorImpl implements ReportCreator { + private static final String SEPARATOR = ","; + private static final String REPORT_HEADER = "fruit,quantity"; + private static final String JOINING_SUFFIX = ""; + private final StorageDao storageDao; + + public ReportCreatorImpl(StorageDao storageDao) { + this.storageDao = storageDao; + } + + @Override + public String createReport() { + return storageDao.getALl().entrySet().stream() + .map(e -> e.getKey().getName() + SEPARATOR + e.getValue()) + .collect(Collectors.joining(System.lineSeparator(), + REPORT_HEADER + System.lineSeparator(), JOINING_SUFFIX)); + } +} diff --git a/src/main/java/core/basesyntax/strategy/OperationStrategy.java b/src/main/java/core/basesyntax/strategy/OperationStrategy.java new file mode 100644 index 0000000000..b7b18caeab --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/OperationStrategy.java @@ -0,0 +1,8 @@ +package core.basesyntax.strategy; + +import core.basesyntax.model.Operation; +import core.basesyntax.service.OperationHandler; + +public interface OperationStrategy { + OperationHandler getOperationHandler(Operation operation); +} diff --git a/src/main/java/core/basesyntax/strategy/impl/OperationStrategyImpl.java b/src/main/java/core/basesyntax/strategy/impl/OperationStrategyImpl.java new file mode 100644 index 0000000000..fae7b71f9e --- /dev/null +++ b/src/main/java/core/basesyntax/strategy/impl/OperationStrategyImpl.java @@ -0,0 +1,20 @@ +package core.basesyntax.strategy.impl; + +import core.basesyntax.model.Operation; +import core.basesyntax.service.OperationHandler; +import core.basesyntax.strategy.OperationStrategy; +import java.util.Map; + +public class OperationStrategyImpl implements OperationStrategy { + private final Map operationHandlerMap; + + public OperationStrategyImpl(Map operationHandlerMap) { + this.operationHandlerMap = operationHandlerMap; + } + + @Override + public OperationHandler getOperationHandler(Operation operation) { + return operationHandlerMap.get(operation); + } +} diff --git a/src/main/resources/data.csv b/src/main/resources/data.csv new file mode 100644 index 0000000000..c771f259d3 --- /dev/null +++ b/src/main/resources/data.csv @@ -0,0 +1,9 @@ +type,fruit,quantity +b,banana,20 +b,apple,100 +s,banana,100 +p,banana,13 +r,apple,10 +p,apple,20 +p,banana,5 +s,banana,50 \ No newline at end of file diff --git a/src/main/resources/report.csv b/src/main/resources/report.csv new file mode 100644 index 0000000000..d7ee69b6d1 --- /dev/null +++ b/src/main/resources/report.csv @@ -0,0 +1,3 @@ +fruit,quantity +banana,152 +apple,90 \ No newline at end of file