Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hw fruit shop #1231

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions fruit,quantity
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
src/main/java/resources/finalReport.csv
9 changes: 0 additions & 9 deletions src/main/java/core/basesyntax/HelloWorld.java

This file was deleted.

61 changes: 61 additions & 0 deletions src/main/java/core/basesyntax/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package core.basesyntax;

import core.basesyntax.dao.FruitStorageDao;
import core.basesyntax.dao.FruitStorageDaoImpl;
import core.basesyntax.model.FruitTransaction;
import core.basesyntax.service.DataConverterService;
import core.basesyntax.service.FileReaderService;
import core.basesyntax.service.FileWriterService;
import core.basesyntax.service.ReportGenerator;
import core.basesyntax.service.ShopService;
import core.basesyntax.service.impl.CsvFormatReportGenerator;
import core.basesyntax.service.impl.DataConverterServiceImpl;
import core.basesyntax.service.impl.FileReaderServiceImpl;
import core.basesyntax.service.impl.FileWriterServiceImpl;
import core.basesyntax.service.impl.ShopServiceImpl;
import core.basesyntax.service.impl.operation.BalanceOperation;
import core.basesyntax.service.impl.operation.OperationHandler;
import core.basesyntax.service.impl.operation.PurchaseOperation;
import core.basesyntax.service.impl.operation.ReturnOperation;
import core.basesyntax.service.impl.operation.SupplyOperation;
import core.basesyntax.strategy.OperationStrategy;
import core.basesyntax.strategy.OperationStrategyImpl;
import java.util.List;
import java.util.Map;

public class Main {
private static final String INPUT_FILE_PATH = "src/main/java/resources/reportToRead.csv";
private static final String OUTPUT_FILE_PATH = "src/main/java/resources/finalReport.csv";
private static final FruitStorageDao FRUIT_STORAGE_DAO = new FruitStorageDaoImpl();

private static final Map<FruitTransaction.Operation, OperationHandler> OPERATION_HANDLERS
= Map.of(FruitTransaction.Operation.BALANCE, new BalanceOperation(FRUIT_STORAGE_DAO),
FruitTransaction.Operation.PURCHASE, new PurchaseOperation(FRUIT_STORAGE_DAO),
FruitTransaction.Operation.RETURN, new ReturnOperation(FRUIT_STORAGE_DAO),
FruitTransaction.Operation.SUPPLY, new SupplyOperation(FRUIT_STORAGE_DAO));

public static void main(String[] arg) {
// 1. Read the data from the input CSV file
FileReaderService fileReader = new FileReaderServiceImpl();
List<String> inputReport = fileReader.read(INPUT_FILE_PATH);

// 2. Convert the incoming data into FruitTransactions list
DataConverterService dataConverter = new DataConverterServiceImpl();
List<FruitTransaction> transactions = dataConverter.convertToTransaction(inputReport);

// 3. Creating OperationStrategy with OperationHandlers
OperationStrategy operationStrategy = new OperationStrategyImpl(OPERATION_HANDLERS);

// 4. Process the incoming transactions with applicable OperationHandler implementations
ShopService shopService = new ShopServiceImpl(operationStrategy);
shopService.process(transactions);

// 5.Generate report based on the current Storage state
ReportGenerator reportGenerator = new CsvFormatReportGenerator(FRUIT_STORAGE_DAO);
String resultingReport = reportGenerator.create();

// 6. Write the received report into the destination file
FileWriterService fileWriter = new FileWriterServiceImpl();
fileWriter.writeToFile(OUTPUT_FILE_PATH, resultingReport);
}
}
12 changes: 12 additions & 0 deletions src/main/java/core/basesyntax/dao/FruitStorageDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package core.basesyntax.dao;

import java.util.Map;
import java.util.Set;

public interface FruitStorageDao {
void setQuantity(String fruitName, Integer quantity);

Integer getQuantity(String fruitName);

Set<Map.Entry<String, Integer>> getAll();
}
25 changes: 25 additions & 0 deletions src/main/java/core/basesyntax/dao/FruitStorageDaoImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package core.basesyntax.dao;

import core.basesyntax.dp.Storage;
import java.util.Map;
import java.util.Set;

public class FruitStorageDaoImpl implements FruitStorageDao {
@Override
public void setQuantity(String fruitName, Integer quantity) {
Storage.storage.put(fruitName, quantity);
}

@Override
public Integer getQuantity(String fruitName) {
if (!Storage.storage.containsKey(fruitName)) {
throw new RuntimeException("There is no " + fruitName + " in the storage");
}
return Storage.storage.get(fruitName);
}

@Override
public Set<Map.Entry<String, Integer>> getAll() {
return Map.copyOf(Storage.storage).entrySet();
RomanChygryn marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +22 to +23

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getAll method uses Map.copyOf(Storage.storage).entrySet(), which creates a copy of the storage map. This might be unnecessary if you only need to read the entries. Consider returning Storage.storage.entrySet() directly if immutability is not a concern, or use Collections.unmodifiableSet to return an unmodifiable view if needed.

}
}
7 changes: 7 additions & 0 deletions src/main/java/core/basesyntax/dp/Storage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package core.basesyntax.dp;

import java.util.HashMap;

public class Storage {
public static final HashMap<String, Integer> storage = new HashMap<>();
RomanChygryn marked this conversation as resolved.
Show resolved Hide resolved

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a static HashMap for storage can lead to concurrency issues if accessed by multiple threads simultaneously. Consider using a thread-safe collection like ConcurrentHashMap if your application will be multi-threaded. Additionally, static fields can make unit testing more challenging, as they maintain state across tests.

}
76 changes: 76 additions & 0 deletions src/main/java/core/basesyntax/model/FruitTransaction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package core.basesyntax.model;

import java.util.Arrays;

public class FruitTransaction {
private Operation operation;
private String fruit;
private int quantity;

public FruitTransaction(Operation operation, String fruit, int quantity) {
this.operation = operation;
this.fruit = fruit;
this.quantity = quantity;
}

public enum Operation {
BALANCE("b"),
SUPPLY("s"),
PURCHASE("p"),
RETURN("r");

private final String letter;

Operation(String operation) {
this.letter = operation;
}

public String getLetter() {
return letter;
}

public static FruitTransaction.Operation getOperation(String letter) {
return Arrays.stream(FruitTransaction.Operation.values())
.filter(a -> a.getLetter().equals(letter))
.findFirst()
.orElseThrow(
() -> new IllegalArgumentException(
"No enum constant for letter: " + letter
)
);
}
Comment on lines +31 to +41

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getOperation method throws an IllegalArgumentException if no matching operation is found. This is a good practice for handling invalid inputs. Ensure that this exception is handled appropriately wherever this method is used to prevent unexpected crashes.

}

public Operation getOperation() {
return operation;
}

public void setOperation(Operation operation) {
this.operation = operation;
}

public String getFruit() {
return fruit;
}

public void setFruit(String fruit) {
this.fruit = fruit;
}

public int getQuantity() {
return quantity;
}

public void setQuantity(int quantity) {
this.quantity = quantity;
}

@Override
public String toString() {
return "FruitTransaction{"
+ "operation=" + operation
+ ", fruit='" + fruit + '\''
+ ", quantity=" + quantity
+ '}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package core.basesyntax.service;

import core.basesyntax.model.FruitTransaction;
import java.util.List;

public interface DataConverterService {
List<FruitTransaction> convertToTransaction(List<String> data);
}
7 changes: 7 additions & 0 deletions src/main/java/core/basesyntax/service/FileReaderService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package core.basesyntax.service;

import java.util.List;

public interface FileReaderService {
List<String> read(String pathToFile);
}
5 changes: 5 additions & 0 deletions src/main/java/core/basesyntax/service/FileWriterService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package core.basesyntax.service;

public interface FileWriterService {
void writeToFile(String pathToFile, String report);
}
5 changes: 5 additions & 0 deletions src/main/java/core/basesyntax/service/ReportGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package core.basesyntax.service;

public interface ReportGenerator {
String create();
}
8 changes: 8 additions & 0 deletions src/main/java/core/basesyntax/service/ShopService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package core.basesyntax.service;

import core.basesyntax.model.FruitTransaction;
import java.util.List;

public interface ShopService {
void process(List<FruitTransaction> transactions);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package core.basesyntax.service.impl;

import core.basesyntax.dao.FruitStorageDao;
import core.basesyntax.service.ReportGenerator;
import java.util.Map;

public class CsvFormatReportGenerator implements ReportGenerator {
private static final String LINE_SEPARATOR = System.lineSeparator();
private static final String CSV_SEPARATOR = ",";
private static final String START_MESSAGE = "fruit,quantity";
private final FruitStorageDao storageDao;

public CsvFormatReportGenerator(FruitStorageDao storageDao) {
this.storageDao = storageDao;
}

@Override
public String create() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(START_MESSAGE);

storageDao.getAll().stream()
.map(Map.Entry::getKey)
.forEach(e -> stringBuilder.append(LINE_SEPARATOR)
.append(e)
.append(CSV_SEPARATOR)
.append(storageDao.getQuantity(e)));
RomanChygryn marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +22 to +27

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the create method, you are calling storageDao.getQuantity(e) inside the forEach loop. This can be inefficient if getQuantity involves complex operations or if the storage is large. Since you already have the entries from getAll(), consider using Map.Entry::getValue to directly access the quantity, which would be more efficient.

return stringBuilder.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package core.basesyntax.service.impl;

import core.basesyntax.model.FruitTransaction;
import core.basesyntax.service.DataConverterService;
import java.util.ArrayList;
import java.util.List;

public class DataConverterServiceImpl implements DataConverterService {
public static final String SEPARATOR = ",";

@Override
public List<FruitTransaction> convertToTransaction(List<String> data) {
List<FruitTransaction> transactions = new ArrayList<>();

for (int i = 1; i < data.size(); i++) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loop starts from index 1, which assumes that the first line of the data is a header. Ensure that this assumption is documented or handled elsewhere if the input data format changes.

String line = data.get(i);
String[] parts = line.split(SEPARATOR);

if (parts.length != 3) {
throw new IllegalArgumentException("Invalid data format: " + line);
}
RomanChygryn marked this conversation as resolved.
Show resolved Hide resolved

try {
FruitTransaction.Operation operation =
FruitTransaction.Operation.getOperation(parts[0].trim().toLowerCase());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getOperation method is called with parts[0].trim().toLowerCase(). Ensure that the operation letters in the input data are consistently formatted in lowercase to avoid unexpected errors.


String fruit = parts[1].trim();
int quantity = Integer.parseInt(parts[2].trim());

FruitTransaction transaction = new FruitTransaction(operation, fruit, quantity);
transactions.add(transaction);
} catch (IllegalArgumentException e) {
throw new RuntimeException("Error parsing line: " + line, e);
RomanChygryn marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +37 to +38

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching IllegalArgumentException and rethrowing it as a RuntimeException with a custom message is a good practice for providing more context. Ensure that this exception handling is consistent throughout the application.

}
}

return transactions;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package core.basesyntax.service.impl;

import core.basesyntax.service.FileReaderService;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

public class FileReaderServiceImpl implements FileReaderService {

@Override
public List<String> read(String pathToFile) {
try {
return Files.readAllLines(Path.of(pathToFile));
} catch (IOException e) {
throw new RuntimeException("Can't read from file: " + pathToFile);
RomanChygryn marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package core.basesyntax.service.impl;

import core.basesyntax.service.FileWriterService;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

public class FileWriterServiceImpl implements FileWriterService {
@Override
public void writeToFile(String pathToFile, String report) {
Path path = Path.of(pathToFile);
try {
Files.writeString(path, report, StandardOpenOption.CREATE);
} catch (IOException e) {
throw new RuntimeException("Can`t write file " + path, e);
RomanChygryn marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
31 changes: 31 additions & 0 deletions src/main/java/core/basesyntax/service/impl/ShopServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package core.basesyntax.service.impl;

import core.basesyntax.model.FruitTransaction;
import core.basesyntax.service.ShopService;
import core.basesyntax.service.impl.operation.OperationHandler;
import core.basesyntax.strategy.OperationStrategy;
import java.util.List;

public class ShopServiceImpl implements ShopService {
private final OperationStrategy operationStrategy;

public ShopServiceImpl(OperationStrategy operationStrategy) {
this.operationStrategy = operationStrategy;
}

@Override
public void process(List<FruitTransaction> transactions) {
for (FruitTransaction transaction : transactions) {
OperationHandler handler =
operationStrategy.getOperationHandler(transaction.getOperation());

if (handler == null) {
throw new IllegalArgumentException(
"No handler found for operation: " + transaction.getOperation()
);
RomanChygryn marked this conversation as resolved.
Show resolved Hide resolved
}
Comment on lines +22 to +26

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code checks if the handler is null and throws an IllegalArgumentException if no handler is found for a given operation. This is a good practice for handling unexpected cases. Ensure that the OperationStrategy is correctly set up to provide handlers for all expected operations to avoid this exception.


handler.doOperation(transaction.getFruit(), transaction.getQuantity());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package core.basesyntax.service.impl.operation;

import core.basesyntax.dao.FruitStorageDao;

public class BalanceOperation implements OperationHandler {
private final FruitStorageDao storageDao;

public BalanceOperation(FruitStorageDao storageDao) {
this.storageDao = storageDao;
}

@Override
public void doOperation(String fruitName, Integer quantity) {
storageDao.setQuantity(fruitName, quantity);
}
}
Loading
Loading