package com.pqt.server.module.stock; import com.pqt.core.entities.product.Product; import com.pqt.server.tools.entities.SaleContent; import com.pqt.server.tools.io.ISerialFileManager; import com.pqt.server.tools.io.SimpleSerialFileManagerFactory; import java.lang.IllegalStateException; import java.util.*; /** * Implémentation de l'interface {@link IStockDao} utilisant un fichier de sauvegarde pour assurer la persistance des * données liées aux produits vendus. *

* Les données sont écrites et lues dans le fichier grâce au méchanisme de sérialisation/désérialisation. Elles ne sont * pas faites pour être lisibles directement par un humain. * * @author Guillaume "Cess" Prost */ public class FileStockDao implements IStockDao { private static final String STOCK_FILE_NAME = "stock.pqt"; private ISerialFileManager fileManager; private long nextProductId; private Random random; private Map products; FileStockDao() { random = new Random(); fileManager = SimpleSerialFileManagerFactory.getFileManager(Product.class, STOCK_FILE_NAME); loadFromFile(); generateNextProductId(); } private void generateNextProductId() { Long newId; do{ newId = random.nextLong(); }while (products.containsKey(newId)); nextProductId = newId; } /** * @see com.pqt.server.module.stock.IStockDao#getProductList() */ public List getProductList() { return copyOfProductList(); } private List copyOfProductList() { List copy = new ArrayList<>(); products.values().forEach(p->copy.add(new Product(p))); return copy; } /** * @see com.pqt.server.module.stock.IStockDao#getProduct(long) */ public Product getProduct(long id) { return products.get(id); } /** * @see com.pqt.server.module.stock.IStockDao#addProduct(com.pqt.core.entities.product.Product) */ public long addProduct(Product product) { product.setId(nextProductId); this.products.put(nextProductId, product); long reply = nextProductId; generateNextProductId(); saveToFile(); return reply; } /** * @see com.pqt.server.module.stock.IStockDao#removeProduct(long) */ public void removeProduct(long id) { Product product = getProduct(id); if(product!=null){ this.products.remove(product.getId()); saveToFile(); } } /** * @see com.pqt.server.module.stock.IStockDao#modifyProduct(long, com.pqt.core.entities.product.Product) */ public void modifyProduct(long id, Product product) { if(this.products.containsKey(id)){ product.setId(id); this.products.put(id, product); saveToFile(); } } @Override public void applySale(SaleContent saleContent) throws IllegalArgumentException { if(saleContent==null) return; try { for(Product product : saleContent.getProductList()){ applyRecursiveStockRemoval(product, saleContent.getProductAmount(product)); applySoldCounterIncrease(product, saleContent.getProductAmount(product)); } saveToFile(); }catch (IllegalStateException e){ loadFromFile(); throw new IllegalArgumentException(e); } } /** * Cette méthode augmente le compteur de vente pour un produit donné dans la BDD. * * @param product données à utiliser pour déterminer le produit correspondant dans la BDD dont les données doivent * être manipulées. * @param amount montant à ajouter * @throws IllegalStateException exception levée si le produit donné ne peut pas être trouvé dans la base de donnée. */ private void applySoldCounterIncrease(Product product, Integer amount) throws IllegalStateException{ Product correspondingProduct = getProduct(product.getId()); if(correspondingProduct!=null){ correspondingProduct.setAmountSold(correspondingProduct.getAmountSold() + amount); }else{ StringBuilder sb = new StringBuilder("StockService>StockDao : Un produit vendu ne correspond pas à un produit connu : "); sb.append(product.getId()).append(" - ").append(product.getName()).append("(").append(product.getCategory()).append(")"); throw new IllegalStateException(sb.toString()); } } /** * Cette méthode retire à un produit donné de la BDD le montant spécifié (diminue la valeur de * {@link Product#amountRemaining}), puis effectue récursivement la même opération pour tous les composants de ce * produit. * * @param product données à utiliser pour déterminer le produit correspondant dans la BDD dont les données doivent * être manipulées. * @param amount montant à déduire * @throws IllegalStateException exception levée si le produit donné ne peut pas être trouvé dans la base de donnée. */ private void applyRecursiveStockRemoval(Product product, int amount) throws IllegalStateException { Product correspondingProduct = getProduct(product.getId()); if(correspondingProduct!=null) { correspondingProduct.setAmountRemaining(correspondingProduct.getAmountRemaining() - amount); correspondingProduct.getComponents().forEach(component -> applyRecursiveStockRemoval(component, amount)); }else{ StringBuilder sb = new StringBuilder("StockService>StockDao : Un produit vendu ne correspond pas à un produit connu : "); sb.append(product.getId()).append(" - ").append(product.getName()).append("(").append(product.getCategory()).append(")"); throw new IllegalStateException(sb.toString()); } } /** * Cette méthode charge les données relatives aux produits depuis le fichier de sauvegarde. Si ce fichier n'existe * pas, il est créé et la liste des produits est vidée. */ private void loadFromFile() { Map loadedData = new HashMap<>(); fileManager.loadListFromFile().forEach(product -> loadedData.put(product.getId(), product)); products = new HashMap<>(loadedData); } /** * Cette méthode écrit les données relatives aux produits dans le fichier de sauvegarde, écrasant le contenu * précédent. */ private void saveToFile() { fileManager.saveListToFile(new ArrayList<>(products.values())); } }